Explain Codes LogoExplain Codes Logo

How to do a JUnit assert on a message in a logger

java
logging
junit
assertions
Nikita BarsukovbyNikita Barsukov·Nov 13, 2024
TLDR

Firstly, create a mock Appender to assert logging content with JUnit. If you are dealing with Log4j2, the TestAppender functionality can be handy to capture logs, thus enhancing your assertions. Here is how you can accomplish it:

import org.apache.logging.log4j.*; import org.apache.logging.log4j.core.*; import org.junit.*; import static org.junit.Assert.*; public class LoggerTest { private final Logger logger = LogManager.getLogger(); private final TestAppender testAppender = new TestAppender(); @Before public void setUp() { // No one else is allowed in our party! ((LoggerContext) LogManager.getContext(false)).getConfiguration().getRootLogger().addAppender(testAppender); } @After public void tearDown() { // Party's over, folks! ((LoggerContext) LogManager.getContext(false)).getConfiguration().getRootLogger().removeAppender(testAppender); } @Test public void logsExpectedMessage() { logger.debug("Test Message"); // Do we spy with our little eye the message we're looking for? assertTrue(testAppender.contains("Test Message")); } private static class TestAppender extends AbstractAppender { private final StringBuilder logContent = new StringBuilder(); TestAppender() { super("TestAppender", null, null); // Let's get this party started! start(); } @Override public void append(LogEvent event) { // Another one bites the dust (gets logged)! logContent.append(event.getMessage().getFormattedMessage()); } public boolean contains(String message) { // Sherlock Holmes mode: ON. return logContent.toString().contains(message); } } }

Attach the TestAppender before tests kick-off and remember to detach it after the tests. Assert the logged messages by using assertTrue, inserting your specific logged content.

Better logging tests: Key techniques

Use ListAppender for direct and easy access

When you want to avoid creating a new class, like a custom Appender, a ListAppender can be your knight in shining armor. ListAppender allows direct and dynamic access to the log entries for making assertions.

Leverage third-party libraries

When you are aiming for a cross-framework solution, think about LogCaptor. Libraries like this cut down the boilerplate code and simplify the way you handle assertion processes.

Mastering System outputs

There will be times when you have to deal with capturing System outputs. During those times, don't forget to register the OutputCaptureExtension. It's a JUnit 5 Extension extremely useful with Spring Boot 2.2 and later versions.

Advanced techniques for experienced Spy... err... Testers

Employing hamcrest matchers

Don't stop at simple assertTrue checks. Use the power of the hamcrest matchers, particularly the assertThat function. Combine these with custom matchers for getting expressive assertions.

Not just what, but how loud

Asserting messages is one part of the game, but checking the log levels is an equally important aspect. Ensure your logger captures the message and tags it with the correct severity or log level.

Logger configurations for clean tests

Ensure your logger doesn't have interference from production loggers. Techniques like the setUseParentHandlers(false) function prevents logging noise during the course of your tests.