How to intercept SLF4J (with logback) logging via a JUnit test?
Is it possible to somehow intercept the logging (SLF4J + logback) and get an InputStream
(or something else that is readable) via a JUnit test case...?
Solution 1:
The Slf4j API doesn't provide such a way but Logback provides a simple solution.
You can use ListAppender
: a whitebox logback appender where log entries are added in a public List
field that we could use to make our assertions.
Here is a simple example.
Foo class :
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Foo {
static final Logger LOGGER = LoggerFactory.getLogger(Foo .class);
public void doThat() {
logger.info("start");
//...
logger.info("finish");
}
}
FooTest class :
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.read.ListAppender;
public class FooTest {
@Test
void doThat() throws Exception {
// get Logback Logger
Logger fooLogger = (Logger) LoggerFactory.getLogger(Foo.class);
// create and start a ListAppender
ListAppender<ILoggingEvent> listAppender = new ListAppender<>();
listAppender.start();
// add the appender to the logger
fooLogger.addAppender(listAppender);
// call method under test
Foo foo = new Foo();
foo.doThat();
// JUnit assertions
List<ILoggingEvent> logsList = listAppender.list;
assertEquals("start", logsList.get(0)
.getMessage());
assertEquals(Level.INFO, logsList.get(0)
.getLevel());
assertEquals("finish", logsList.get(1)
.getMessage());
assertEquals(Level.INFO, logsList.get(1)
.getLevel());
}
}
You can also use Matcher/assertion libraries as AssertJ or Hamcrest.
With AssertJ it would be :
import org.assertj.core.api.Assertions;
Assertions.assertThat(listAppender.list)
.extracting(ILoggingEvent::getFormattedMessage, ILoggingEvent::getLevel)
.containsExactly(Tuple.tuple("start", Level.INFO), Tuple.tuple("finish", Level.INFO));
Solution 2:
You can create a custom appender
public class TestAppender extends AppenderBase<LoggingEvent> {
static List<LoggingEvent> events = new ArrayList<>();
@Override
protected void append(LoggingEvent e) {
events.add(e);
}
}
and configure logback-test.xml to use it. Now we can check logging events from our test:
@Test
public void test() {
...
Assert.assertEquals(1, TestAppender.events.size());
...
}
NOTE: Use ILoggingEvent
if you do not get any output - see the comment section for the reasoning.