單元測試中驗(yàn)證日志

一般來說,日志是程序相當(dāng)次要的副作用輸出,很少需要專門的單元測試來保證它的行為。不過也不排除在某些情況下需要在單元測試中驗(yàn)證日志,比如:

  • 某個(gè)場景下日志輸出是下游模塊的關(guān)鍵信息。一般出現(xiàn)在錯(cuò)誤處理分支中。
  • 某個(gè)模塊除了日志沒有顯著的輸出來檢驗(yàn)它的行為。紅燈,模塊可測試性差的表現(xiàn)。

這里介紹以比較常用的logbacklog4j2為例介紹驗(yàn)證日志的方法,以備不時(shí)之需。

被測試代碼

public class SampleService {
    private static Logger LOG = LoggerFactory.getLogger(SampleService.class);
    @Autowired SampleDependency dependency;

    public String foo() {
        LOG.info("starting foo");
        String bar = "";
        try {
            bar = dependency.getExternalValue("bar");
        } catch (Exception e) {
            System.out.println(LOG.getClass().getTypeName());
            LOG.error("calling foo error", e);
        }
        return bar;
    }
}

因?yàn)閮煞N框架外加slf4j中有很多同名的類,示例代碼中全部帶上完整包名以免混淆。

Logback

@Test
public void testLogback() {
    //given
    ch.qos.logback.core.Appender<ch.qos.logback.classic.spi.ILoggingEvent> appender = mock(ch.qos.logback.core.Appender.class);
    ((ch.qos.logback.classic.Logger) LoggerFactory.getLogger(SampleService.class)).addAppender(appender);
    doThrow(new RuntimeException("something wrong...")).when(dependency).getExternalValue(anyString());

    //when
    service.foo();

    //then
    ArgumentCaptor<ch.qos.logback.classic.spi.ILoggingEvent> logCaptor = ArgumentCaptor.forClass(ch.qos.logback.classic.spi.ILoggingEvent.class);
    //通過ArgumentCaptor捕獲所有l(wèi)og,
    //verify默認(rèn)是一次調(diào)用,改為atLeast(0)讓任意次數(shù)記錄log都能驗(yàn)證通過
    verify(appender, atLeast(0)).doAppend(logCaptor.capture()); 
    logCaptor.getAllValues().stream()
            .filter(event -> event.getFormattedMessage().equals("calling foo error"))
            .findFirst().orElseThrow(AssertionError::new);
}

Log4j2

@Test
public void testLog4J2() {
    //given
    org.apache.logging.log4j.core.Appender appender = mock(org.apache.logging.log4j.core.Appender.class);
    when(appender.getName()).thenReturn("mocked");  //加入appender時(shí)需要
    when(appender.isStarted()).thenReturn(true);  //使appender生效時(shí)需要
    ((org.apache.logging.log4j.core.Logger) org.apache.logging.log4j.LogManager.getRootLogger() ).addAppender(appender);
    doThrow(new RuntimeException("something wrong...")).when(dependency).getExternalValue(anyString());

    //when
    service.foo();

    //then
    ArgumentCaptor<org.apache.logging.log4j.core.LogEvent> logCaptor = ArgumentCaptor.forClass(org.apache.logging.log4j.core.LogEvent.class);
    verify(appender, atLeast(0)).append(logCaptor.capture());
    logCaptor.getAllValues().stream()
            .filter(event -> event.getMessage().getFormattedMessage().equals("calling foo error"))
            .findFirst().orElseThrow(AssertionError::new);
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,533評論 19 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 47,261評論 6 342
  • 在項(xiàng)目開發(fā)過程中,我們可以通過 debug 查找問題。而在線上環(huán)境我們查找問題只能通過打印日志的方式查找問題。因此...
    Java架構(gòu)閱讀 3,572評論 2 41
  • 歷史 log4j可以當(dāng)之無愧地說是Java日志框架的元老,1999年發(fā)布首個(gè)版本,2012年發(fā)布最后一個(gè)版本,20...
    kelgon閱讀 10,290評論 3 53
  • 作為Java開發(fā)人員,對于日志記錄框架一定非常熟悉。而且?guī)缀踉谒袘?yīng)用里面,一定會(huì)用到各種各樣的日志框架用來記錄程...
    意識(shí)流丶閱讀 14,458評論 0 13

友情鏈接更多精彩內(nèi)容