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
相关产品推荐
相关产品推荐

