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;
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);
}
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());
}
I hope this might be eventually helpful when you face such a particular scenario! ;-)
Top comments (3)
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.
Thanks a lot! It helped and was the easier solution that I've found.
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.