[JAVA] Validation of log messages using mockito

Describes how to use Mockito to verify log messages in Unit tests.

environment

The main libraries are as follows

Library version
Junit 4.12
mockito 1.10.19
log4j 2.6.2

I am using Maven. Please refer to the link below for the detailed version. pom.xml

Test target

The classes to be tested are as follows. Calling the sayHello method prints a message to the log at the INFO level. Log output uses log4j.

HelloWorld.java


class HelloWorld {
    private Logger logger = LogManager.getLogger(this);

    void sayHello(String name) {
        logger.info("Hello " + name);
    }
}

Test code

You will need an Appender Mock object to get the log messages. We also prepare an ArgumentCaptor to get the value of the argument from the Mock object.

HelloWorldTest.java


    @Mock
    private Appender mockAppender;

    @Captor
    private ArgumentCaptor<LogEvent> logCaptor;

Set the Appender object prepared above to log4j. At this time, specify the value to be returned by Mockito so that it will operate as an Appender when the mockAppender object is called from log4j.

HelloWorldTest.java


        Mockito.reset(mockAppender);
        //Set the name of the Appender
        Mockito.when(mockAppender.getName()).thenReturn("MockAppender");
        //Set to be ready to be used as an Appender (bottom 2 lines)
        Mockito.when(mockAppender.isStarted()).thenReturn(true);
        Mockito.when(mockAppender.isStopped()).thenReturn(false);

        //Take out the ROOT logger and set the Appender.
        LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
        Configuration config = ctx.getConfiguration();

        LoggerConfig loggerConfig = config.getLoggerConfig(LogManager.ROOT_LOGGER_NAME);

        loggerConfig.setLevel(Level.INFO);
        loggerConfig.addAppender(mockAppender, Level.INFO, null);
        ctx.updateLoggers();

The actual test code is as follows. Extract the message from the Appender's append method. You can also check the number of calls. This time, it is clearly specified as 1 because it is once.

HelloWorldTest.java


    @Test
    public void outputLogMessage() {
        String name = "World";

        HelloWorld helloWorld = new HelloWorld();
        helloWorld.sayHello(name);

        Mockito.verify(mockAppender, Mockito.times(1)).append(logCaptor.capture());

        String message = logCaptor.getValue().getMessage().getFormattedMessage();
        Level level = logCaptor.getValue().getLevel();
        assertThat(message, is("Hello " + name));
        assertThat(level, is(Level.INFO));
    }

Summary

Described how to verify log messages by using Mockito to get the arguments of Appender's append object. This allows for log-level verification as well as messages.

Before I knew how to do this, I had a lot of trouble parsing the strings output to the log file. Say goodbye to such hardships.

Set of code

The source code is available below. If you want to try it out, please refer to it.

https://github.com/hiroyuki-kaneko/testforlog

Recommended Posts

Validation of log messages using mockito
Implementation of validation using regular expressions
Customization of validation
Rails: Japanese localization of validation messages including devise
Implementation of flash messages
Example of using vue.config.js
Summary of using FragmentArgs
Summary of using DBFlow
Example of params using where
Japanese localization of error messages
Summary of using Butter Knife
Example of using abstract class
Signing and validation using java.security.Provider
Rate-Limiting using RateLimiter of Resilience4j