How to intercept SLF4J (with logback) logging via a JUnit test?

后端 未结 8 900
天涯浪人
天涯浪人 2020-12-04 10:52

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...?

8条回答
  •  独厮守ぢ
    2020-12-04 11:30

    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 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 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));
    

提交回复
热议问题