You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Groovy+Spock:使用@Slf4j AST标签检测日志输出的测试问题

解决MissingMethodException并实现Spock日志验证

嘿,我来帮你搞定这个问题!你遇到的MissingMethodException是因为@Slf4j AST转换生成的log字段是私有且不可变的,它不会自动生成setLog()方法,直接调用肯定行不通。下面分两步帮你解决:

一、先搞定报错:为什么setLog()不存在?

@Slf4j给类生成的log字段是private final的,Groovy不会为这种字段自动生成setter方法。如果想在测试里替换Logger实例,用Groovy的反射特性就能轻松修改私有字段:

def "测试error日志输出"() {
    given:
    def consoleHandler = new core.ConsoleHandler()
    def testLogger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger("testLogger")
    // Groovy直接修改私有final字段的简洁写法
    consoleHandler.@log = testLogger

    when:
    consoleHandler.start() // start会调用loop方法

    then:
    // 后续验证逻辑
}

不过更推荐的是不替换Logger,而是直接捕获日志输出——这种方式更贴合logback的使用习惯,测试也更可靠。

二、用Spock+Logback Appender捕获并验证Error日志

我们可以创建一个临时的内存Appender来存储日志事件,然后验证是否有error级别的日志输出:

1. 定义MemoryAppender

先写一个简单的内存Appender,用来收集日志:

import ch.qos.logback.classic.spi.ILoggingEvent
import ch.qos.logback.core.AppenderBase

class MemoryAppender extends AppenderBase<ILoggingEvent> {
    List<ILoggingEvent> events = []

    @Override
    protected void append(ILoggingEvent event) {
        events.add(event)
    }

    void reset() {
        events.clear()
    }
}

2. 编写Spock测试用例

在测试里动态给目标Logger添加这个Appender,调用方法后验证日志:

import ch.qos.logback.classic.Logger
import org.slf4j.LoggerFactory
import spock.lang.Specification

class ConsoleHandlerSpec extends Specification {

    def "验证start方法触发error级别日志"() {
        given:
        def consoleHandler = new core.ConsoleHandler()
        // 获取被测类对应的Logger
        Logger targetLogger = (Logger) LoggerFactory.getLogger(core.ConsoleHandler)
        def memoryAppender = new MemoryAppender()
        // 初始化并添加Appender到Logger
        memoryAppender.context = targetLogger.context
        memoryAppender.start()
        targetLogger.addAppender(memoryAppender)

        when:
        consoleHandler.start() // start调用loop方法,预期会产生error日志

        then:
        // 验证是否存在error级别的日志
        def errorEvents = memoryAppender.events.findAll { it.level == ch.qos.logback.classic.Level.ERROR }
        errorEvents.size() > 0
        // 还可以验证日志内容是否符合预期
        errorEvents.any { it.message.contains("你预期的错误关键词") }

        cleanup:
        // 清理Appender,避免影响其他测试用例
        targetLogger.detachAppender(memoryAppender)
        memoryAppender.stop()
    }
}

小提醒

如果你的loop方法是异步执行的,记得在测试里加一点等待逻辑(比如Thread.sleep()或者Spock的waitFor),确保日志已经被捕获再做验证。

内容的提问来源于stack exchange,提问作者mike rodent

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 10:03:50