在不使用 Log4J 的情况下测试 Slf4j 创建的日志消息

Testing Log Messages Created by Slf4j Without Using Log4J

我想测试一种方法是否创建了正确的日志。我的 class 看起来像这样:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;

class EventLogHandler {
    private final Logger logger = LoggerFactory.getLogger(EventLogHandler.class);
    private final Marker eventMarker = MarkerFactory.getMarker("EVENT");

    public void handle(final Event event) {
        final String log = SomeOtherClass.createLog(event);
        logger.info(eventMarker, log);
    }
}

我看到一些examples/solutions用于测试日志,但它们都在使用我们在项目中没有使用的Log4j。我只能用spring-boot的Log4j2,Slf4j和Logback classic。 我如何用现有的依赖项测试 handle(...) 方法?

在当前的实现中,您不能 test/verify 在 logger 上调用而不使用日志系统并断言其输出,例如引入 logback 并使用 stdout appender 配置它并捕获 stdout 并对其进行断言等。

为了在不执行任何操作的情况下测试您的 class,您必须亲身体验 EventLogHandler 中使用的 logger 实例。当前的实现通过像这样构建 logger 来增加难度:

private final Logger logger = LoggerFactory.getLogger(EventLogHandler.class);

在这种情况下进行测试的一种常见方法是重构记录器的创建,以便在 运行 测试时将模拟实例注入 EventLogHandler。例如:

class EventLogHandler {
    private final Marker eventMarker = MarkerFactory.getMarker("EVENT");
    private final Logger logger;

    public EventLogHandler() {
        this(LoggerFactory.getLogger(EventLogHandler.class));
    }

    // probably only used by your test case
    public EventLogHandler(Logger logger) {
        this.logger = logger;
    }

    public void handle(final Event event) {
        logger.info(eventMarker, log);
    }
}

然后像这样测试它:

@Test
public void someTest() {
    Logger logger = Mockito.mock(Logger.class);
    EventLogHandler sut = new EventLogHandler(logger);

    sut.handle(event);

    // verify that the right state is extracted from the given event and that the correct marker is used
    Mockito.verify(logger).info(..., ...);
}

一个不太常见的替代方法是使用 Powermock 来模拟此调用:LoggerFactory.getLogger(EventLogHandler.class); 然后使用 Mockito 以与上面所示相同的方式验证对其的调用..