Reputation: 7394
Below is a method that I am attempting to write Junit test for:
Method I wish to test:
//logger declared outside of method in Class
private static Logger LOGGER = LoggerFactory.getLogger(PersonService.class);
public void showOutputOfIdentifications(int age) {
if(age>25){
LOGGER.info("Over 25");
}else{
LOGGER.info("25 or Under");
}
}
How can I test to verify that the correct Logback
Log statement has been called?
In my tests I have tried to mock the logger
and verify that it was called, however this has not worked?
Current Test Attempt:
@Test
public void testShowOutputOfIdentifications() throws ParseException{
int age = 10;
Logger LOGGER_mock = mock(Logger.class);
//call method under test
showOutputOfIdentifications(age);
verify(LOGGER_mock).info("25 or under");
}
Current failing test output:
Wanted but not invoked:
logger.info(
"25 or under "
);
Actually, there were zero interactions with this mock.
Upvotes: 8
Views: 18418
Reputation: 382
You could add your own appender and assert that the log message was written that way, see Programmatically configure LogBack appender.
Something like this:
// create the mock appender
Appender mockedAppender = Mockito.mock(Appender.class);
// inject it
((ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME)).addAppender(mockedAppender);
// run your test
LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME).error("Test msg");
// verify using ArgumentCaptor
ArgumentCaptor<Appender> argumentCaptor = ArgumentCaptor.forClass(Appender.class);
Mockito.verify(mockedAppender).doAppend(argumentCaptor.capture());
// assert against argumentCaptor.getAllValues()
Assert.assertEquals(1, argumentCaptor.getAllValues().size());
Assert.assertEquals("Test msg", ((LoggingEvent)argumentCaptor.getAllValues().get(0)).getMessage());
// remove the mock appender from static context
((Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME)).detachAppender(mockedAppender);
Upvotes: 21
Reputation: 76
I wrote this using Groovy and Spock to Mock the appenders.
My logback-test.xml file looks like
<configuration debug="true">
<statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener"/>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="JSON" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%msg%n</pattern>
</encoder>
</appender>
<logger name="clicks" level="INFO" additivity="false">
<appender-ref ref="JSON"/>
</logger>
<logger name="com.carsnip" level="DEBUG"/>
<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>
And my test contains:
class LogTest extends Specification{
def "should log"() {
given:
Logger root = (Logger)
LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
Appender rootMockAppender = Mock()
root.addAppender(rootMockAppender);
Logger click = (Logger) LoggerFactory.getLogger("clicks");
Appender clickMockAppender = Mock()
click.addAppender(clickMockAppender);
when:
click.info("HEYYYYY")
then:
0 * rootMockAppender.doAppend(_)
1 * clickMockAppender.doAppend(_)
}
}
This is written to check the additivity attribute, so that the ROOT logger, which is higher up in the hierarchy does not pick up the logs from our clicks logger which is going to a different location.
Upvotes: 2