美文网首页TDD(测试驱动开发)
单元测试中验证日志

单元测试中验证日志

作者: 武可 | 来源:发表于2018-09-14 18:16 被阅读451次

一般来说,日志是程序相当次要的副作用输出,很少需要专门的单元测试来保证它的行为。不过也不排除在某些情况下需要在单元测试中验证日志,比如:

  • 某个场景下日志输出是下游模块的关键信息。一般出现在错误处理分支中。
  • 某个模块除了日志没有显著的输出来检验它的行为。红灯,模块可测试性差的表现。

这里介绍以比较常用的logbacklog4j2为例介绍验证日志的方法,以备不时之需。

被测试代码

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

因为两种框架外加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捕获所有log,
    //verify默认是一次调用,改为atLeast(0)让任意次数记录log都能验证通过
    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时需要
    when(appender.isStarted()).thenReturn(true);  //使appender生效时需要
    ((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);
}

相关文章

  • 单元测试中验证日志

    一般来说,日志是程序相当次要的副作用输出,很少需要专门的单元测试来保证它的行为。不过也不排除在某些情况下需要在单元...

  • 使用LogCaptor对日志进行单元测试

    1 为什么要对日志进行单元测试 对代码中打印的日志,是否有必要通过单元测试保证日志的格式、内容能够被正确的修改?答...

  • 软件测试学习教程:单元测试之UnitTest测试框架

    单元测试的概念 单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。 对于单元测试中...

  • 入门单元测试(javaScript篇)

    单元测试的定义 单元测试(Unit Testing),是指对软件中的最小可测试单元进行检查和验证。对于单元测试中单...

  • 一、python 单元测试概述

    一、单元测试概述 单元测试(unit testing )是指对软件中最小可测试单元进行检查和验证,对于单元测试中...

  • 关于单元测试的讨论

    什么是单元测试 单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。 单元测试的作用...

  • 软件测试的分类(一)

    按测试阶段来分类 单元测试,集成测试,系统测试,验收测试 单元测试1.什么是单元测试?对软件中的进行检查和验证。 ...

  • 单元测试(Junit+Jmockit)介绍及使用方法

    名称解释 单元测试(unit testing) 是指对软件中的最小可测试单元进行检查和验证。对于单元测试中单元的含...

  • Android 基础之单元测试

    Android 中的单元测试,是应用程序测试策略中的基本测试,通过对代码进行单元测试,可以轻松地验证单个单元的逻辑...

  • iOS 单元测试

    啥是单元测试 单元测试,是指对软件中的最小可测试单元进行检查和验证。对于单元测试中单元的含义,一般来说,要根据实际...

网友评论

    本文标题:单元测试中验证日志

    本文链接:https://www.haomeiwen.com/subject/riwogftx.html