用 Spock 模拟 slf4j

Mocking slf4j with Spock

我有一个用 @Slf4j 注释的 Groovy class,所以它有一个私有的最终 Logger log 字段,我想测试它的用法。我想继续使用 @Slf4j 并且不再公开 log 字段只是为了启用测试。

我正在使用 Spock 1.0 编写测试,并尝试使用 Spock 的集成模拟和存根功能来完成此测试。全局存根应该帮助我拦截 LoggerFactory 调用以获取实际的 Logger 实例,所以我目前的猜测是:

LoggerFactory logFactory = GroovyStub(global: true)
logFactory.getLogger(_) >> Mock(Logger)
// create my @Slf4j-annotated object afterwards

有趣的是,拦截确实有效,println 确认 class 实际上得到了一个对象 Mock for type 'Logger' named 'dummy',但是指示存根 return 的第二条语句模拟似乎没有抓住。相反,默认存根行为 return 是另一个存根,当然不能用于模拟:

org.spockframework.runtime.InvalidSpecException: Stub 'dummy' matches the following required interaction:

1 * plugin.log.warn(_)   (0 invocations)

Remove the cardinality (e.g. '1 *'), or turn the stub into a mock.

我需要更改什么才能让 stubbed LoggerFactory return 成为 mock Logger?

如果你想测试日志输出,为什么不让日志框架完成它们的工作并测试结果(日志文件)?您只需要将日志输出连接到您在测试具有 运行.

后访问的文件

这可能会导致不那么脆弱的测试。

您需要使用反射设置私有最终日志字段,如下所述:Unit testing of a class with StaticLoggerBinder

您可以使用 slf4j 测试后端来断言 spf4j-slf4j-test 之类的日志记录行为。 Slf4j 将在你的类路径中选择第一个后端实现,这就是为什么你需要在你的项目依赖项中首先列出测试后端依赖项。 (在测试范围内)。