Testing Logging Output in Java
One of my more popular posts on this site is on how to use Mockito to mock logging.
Testing that the logged output is as expected seems to be on the cusp of a good/bad idea. Is the logged output the intended behaviour of the application? or is it an implementation detail that youâre just mirroring in a test?
Arguably, itâs sometimes the formerâĶ logging is the sort of thing that matters when it matters.
Iâd argue that itâs often too low level a thing to be testing, but itâs a critical thing to test when:
- Youâre writing a logging framework that centralises the logging logic
- You have some exceptional case that MUST be logged differently and need to lock down the behaviour
- Logging IS the logic for some reason
Note, I like to think of tests as locking down the logic â we wrote the code this way today, hopefully using TDD, to achieve something observable by a test. The test keeps that observable behaviour from disappearing by going red if someone breaks it. So the test locks down some spec.
Logging in the Modern World
If you want to Mock Log4j2, then go for it. Iâve recently come across something easier.
These days we deliberately log to the System console, rather than log files. This works well when weâre containerising our application, or writing an AWS Lambda, and we want the hosting environmentâs log scraper to pull the logs from stdout rather than mine log files as we write them.
Spooling log messages to the console, while once thought of as a no-no, is essentially a lot cleaner than telling a logging agent to go and read a file as we write it.
Canât We Just Watch System.out Then?
Well, indeed we can. No need to register a listener into the logging framework. Letâs just look at what appears on the console. We can configure our logger to write to the console â in fact it probably does already!
Enter System Stubs
I will write more about it in due course, but System Stubs is a testing library Iâve worked hard on in recent weeks. It started life as a different project that I forked, and then I essentially reworked it to fit in with the sort of tests Iâve been writing. As such, itâs available as a JUnit 5 extension (as well as in other forms).
Letâs imagine we have some code under test thatâs going to do some logging, and we want to see if a certain message appears.
Hereâs a test:
@ExtendWith(SystemStubsExtension.class)
class TheOneAboutTheLoggingTest {
@SystemStub
private SystemOut systemOut;
@Test
void youKnow_ForLogging() {
doTheThingThatShouldLog();
assertThat(systemOut.getLines())
.anyMatch(line -> line.contains("ERROR This is bad!"));
}
}Letâs just unpack a few of the elements in the above.
Thereâs the JUnit 5 extension â SystemStubsExtension. No big deal. Then thereâs a SystemOut object, which is used to capture System.out while the object is active. The object is created by the extension and is activated just before the test, then cleared up afterwards.
While the test is running, System.out is not appearing in the console, itâs being stored in the memory of the SystemOut objectâs TapStream.
At any point we can expect the lines of text that have appeared on System.out. The getLines function provides a Stream<String> which we inspect here using AssertJ.
Given logging output usually contains timestamps, this method requires us to do some sort of substring checking to avoid having to predict the timestamp. Perhaps a future library might help parse the output a little more.
Itâs also worth noting that NOT seeing the logging output on the console is a little annoying during this sort of test. In due course, Iâm planning to release version 1.2.0 of SystemStubs which will allow a multiplex where the output appears on the console AND is also tapped. See this proposed README for more.
So is Tapping System.out the Future of Log Testing?
Yes and no.
Itâs enormously convenient and easy to do. So, Iâm inclined to default to it.
However, for fine-grained testing of exactly what is being sent to the logging library, the reading of strings from a console is a bit messy.
| Published on Java Code Geeks with permission by Ashley Frieze, partner at our JCG program. See the original article here: Testing Logging Output in Java Opinions expressed by Java Code Geeks contributors are their own. |

