JUnit
Logger Messages
Unit Testing
Assertion Methods
Java Programming

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

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

When developing Java applications, testing plays a crucial role in ensuring the code runs as expected. Among various testing frameworks for Java, JUnit is one of the most popular for unit testing. Coupled with assertions for verifying expected results, JUnit helps maintain code reliability. However, testing whether certain expected logs are generated by an application can be equally important, especially when verifying error handling and internal state changes which are reflected only through logging.

To assert log messages in a JUnit test, you can't use JUnit's standard assertions directly because logger messages are typically written to external systems, like console or file systems, and not returned by methods as typical return values. To enable assertions on messages logged during tests, you need to intercept and record these messages first. We can achieve this by using a custom log appender or by utilizing existing libraries which can mock the logging behavior.

Using a Custom Log Appender

A common approach to verify log output is to create a custom log appender. For this example, we are considering Log4j2, a popular logging framework. You can extend the AppenderSkeleton to create an appender that stores log messages in a way that they can be inspected later in the test.

  1. Create a Custom Appender. Define a class that extends AppenderSkeleton. In the append method, store the logging events or messages.
java
1    import org.apache.log4j.AppenderSkeleton;
2    import org.apache.log4j.spi.LoggingEvent;
3
4    public class TestLogAppender extends AppenderSkeleton {
5        private final List<LoggingEvent> log = new ArrayList<>();
6
7        @Override
8        protected void append(LoggingEvent event) {
9            log.add(event);
10        }
11
12        @Override
13        public void close() {}
14
15        @Override
16        public boolean requiresLayout() {
17            return false;
18        }
19
20        public List<LoggingEvent> getLog() {
21            return new ArrayList<>(log);
22        }
23
24        public void clearLog() {
25            log.clear();
26        }
27    }
  1. Set Up and Use in JUnit Test. Before your test runs, add this appender to the logger and remove it afterward.
java
1    import org.apache.log4j.Logger;
2    import org.junit.*;
3
4    public class LoggerTest {
5        private static final Logger logger = Logger.getLogger(MyClassBeingTested.class);
6        private static TestLogAppender testAppender;
7
8        @BeforeClass
9        public static void setUpClass() {
10            testAppender = new TestLogAppender();
11            logger.addAppender(testAppender);
12        }
13
14        @AfterClass
15        public static void tearDownClass() {
16            logger.removeAppender(testAppender);
17        }
18
19        @Test
20        public void testErrorLogging() {
21            MyClassBeingTested obj = new MyClassBeingTested();
22            obj.doSomethingThatLogsAnError();
23
24            boolean errorLogged = testAppender.getLog().stream()
25                .anyMatch(event -> event.getRenderedMessage().contains("Expected error message"));
26            assertTrue("Error message was not logged", errorLogged);
27        }
28    }

Utilizing Mocking Frameworks

Libraries like Mockito can also mock logger behavior, simplifying the testing of log outputs without modifying the actual logging configuration.

  1. Mock Logger. Use Mockito to mock a logger and then verify after the method call that the logger was called with the expected level and message.
java
1    import static org.mockito.Mockito.*;
2    
3    public class LoggerTest {
4        private Logger mockLogger = mock(Logger.class);
5        private MyClassBeingTested testClass = new MyClassBeingTested(mockLogger);
6
7        @Test
8        public void testErrorLogging() {
9            testClass.doSomethingThatLogsAnError();
10            verify(mockLogger).error("Expected error message");
11        }
12    }

Summary Table

ApproachProsCons
Custom Log AppenderFull control over log capture; doesn't need third party libraries except logging frameworkAdditional class code; tightly coupled with specific logging framework
Mocking FrameworksSimpler, less code; better for unit tests focused on behaviorLess suitable if exact formatting or multiple log entries need to be verified

Each approach has its advantages depending on the test scenario and requirements. For simpler use cases where only the occurrence and level of log messages matter, using Mockito or another mocking library might be preferred. For scenarios where exact log content, order, or format matter, a custom appender provides finer control.


Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.