Skip to content

Instantly share code, notes, and snippets.

@bloodredsun
Last active March 9, 2022 08:16
Show Gist options
  • Star 35 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save bloodredsun/a041de13e57bf3c6c040 to your computer and use it in GitHub Desktop.
Save bloodredsun/a041de13e57bf3c6c040 to your computer and use it in GitHub Desktop.
Unit testing logback based logging statements
package com.brs;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Simple class that we use to trigger a log statement.
*/
public class ExampleThatLogs {
private static final Logger LOG = LoggerFactory.getLogger(ExampleThatLogs.class);
public String concat(String a, String b) {
LOG.info("String a:" + a + ", String b:" + b);
return a+b;
}
}
package com.brs;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.spi.LoggingEvent;
import ch.qos.logback.core.Appender;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.slf4j.LoggerFactory;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.verify;
/**
* Our Test class shows how we can hook into logback with mockito to see the
* logging activity
*/
@RunWith(MockitoJUnitRunner.class)
public class ExampleThatLogsTest {
@Mock
private Appender mockAppender;
//Captor is genericised with ch.qos.logback.classic.spi.LoggingEvent
@Captor
private ArgumentCaptor<LoggingEvent> captorLoggingEvent;
//I've cheated a little here and added the mockAppender to the root logger
//It's not quite necessary but it also shows you how it can be done
@Before
public void setup() {
final Logger logger = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
logger.addAppender(mockAppender);
}
//Always have this teardown otherwise we can stuff up our expectations. Besides, it's
//good coding practise
@After
public void teardown() {
final Logger logger = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
logger.detachAppender(mockAppender);
}
@Test
public void shouldConcatAndLog() {
//given
ExampleThatLogs example = new ExampleThatLogs();
//when
final String result = example.concat("foo", "bar");
//then
assertEquals("foobar", result);
//Now verify our logging interactions
verify(mockAppender).doAppend(captorLoggingEvent.capture());
//Having a genricised captor means we don't need to cast
final LoggingEvent loggingEvent = captorLoggingEvent.getValue();
//Check log level is correct
assertThat(loggingEvent.getLevel(), is(Level.INFO));
//Check the message being logged is correct
assertThat(loggingEvent.getFormattedMessage(),
is("String a:foo, String b:bar"));
}
}
@coryellenberger
Copy link

Very helpful

@klassounski-daitan
Copy link

Could you show me the pom please? I'm having a problem and probably because of the packages versions.
I'm getting:

Wanted but not invoked:
mockAppender.doAppend();
-> at com.br.ExampleThatLogsTest.shouldConcatAndLog(ExampleThatLogsTest.java:61)
Actually, there were zero interactions with this mock.

@birqan
Copy link

birqan commented May 24, 2017

A big and fat THANK YOU for your share. Thumbs up!

@abbas-mohamad
Copy link

Very Helpful! Thank You!

@mallesh-np
Copy link

Can you please share your logback.xml?

@nvlinh
Copy link

nvlinh commented May 21, 2018

I use @RunWith(SpringJUnit4ClassRunner.class) for run it, but not work, please tell me the way use it with @RunWith(SpringJUnit4ClassRunner.class)

@manueldeveloper
Copy link

So handy! Thanks!

@kkrz93
Copy link

kkrz93 commented Dec 28, 2020

Thank you!

@jd185368
Copy link

I had the same code but all my logger imports were from log4j package due to which I was getting error while doing Mockito.verify()

Error : Wanted but not invoked:
mockAppender.doAppend();
Actually, there were zero interactions with this mock.

After looking at your code, I changed all my imports to logback and it worked like a charm!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment