DEV Community

Claudio Higashi
Claudio Higashi

Posted on

Mocking Logger in Java with Mockito

Yes, you read it correctly: "Mocking Logger in Java". That might sound very weird when you see this for the first time but there are some particular cases in which the only way to unit test some parts of your application is by checking whether some specific messages were logged or not.

For example, suppose that your application needs to make an asynchronous call to some other WebService. Then you have separate threads for making that call. For the main thread, it doesn't matter if the call to the service was successful or not because it won't wait for a response (otherwise it would be synchronous, right?). Suppose that this part of your application will just call the service and, after that, only log whether the call was successful or not (needless to say that in such a case, you need a monitoring tool in place to know when things are not going well in production).

Now, you have to create a JUnit test case to cover these scenarios. If you google it, you are going to find some people using PowerMock for this, but imagine that you are already using Mockito and, for some reason, you want to do this using Mockito only.

In this post I'm assuming that you are already familiar with Mockito, so I'll focus on the "mocking logger" part only. You can find lots of Mockito tutorials on the Internet if you want to learn it.

Okay. One way to accomplish this is to mock the Appender of your Logger object and use Mockito's ArgumentCaptor to capture all logging events in your test case:

    @Mock
    private Appender mockedAppender;

    @Captor
    private ArgumentCaptor<LoggingEvent> loggingEventCaptor;
Enter fullscreen mode Exit fullscreen mode

Then you have to make sure that the mocked Appender is added to root Logger before the tests are executed:

    @Before
    public void setup() {
        Logger root = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
        root.addAppender(mockedAppender);
        root.setLevel(Level.INFO);
    }
Enter fullscreen mode Exit fullscreen mode

After this you are ready to call the tested class and do the assertions on the logged messages:

    @Test
    public void testSuccessCall() throws Exception {
        // mock all required response objects in here

        [...]

        // this is the call to the service being tested
        myService.execute(createRequestForSuccessResponse());

        // check how many times the ArgumentCaptor was called
        verify(mockAppender, times(1)).doAppend(loggingEventCaptor.capture());
        // get the reference to the LoggingEvent you want to inspect
        LoggingEvent loggingEvent = loggingEventCaptor.getAllValues().get(0);
        // check the logged message
        assertEquals("Webservice was successfully called", loggingEvent.getMessage());
        // check the log level
        assertEquals(Level.INFO, loggingEvent.getLevel());
    }
Enter fullscreen mode Exit fullscreen mode

I hope this might be eventually helpful when you face such a particular scenario! ;-)

Top comments (3)

Collapse
 
vifierlockla profile image
Vifier-Lockla • Edited

Finally I used this excelllent solution well documented : github.com/Hakky54/log-captor
Source code is available : I have just to take time to understand it.

Collapse
 
raulbsantos profile image
Raul Santos • Edited

Thanks a lot! It helped and was the easier solution that I've found.

Collapse
 
vifierlockla profile image
Vifier-Lockla • Edited

Could you list libraries imported for this use case please ? (which Logger). Without that, it's impossible to test your code. It could be better to demonstrate you solution with small github project or provide a whole use case with source code in this page.