首先,记录失败的测试是您的测试框架(JUnit、Spock)的工作。因此,测试本身的状态不容易从测试本身中获得也就不足为奇了。无论如何,如果您想要 Spock 中更高级的东西,那么另一个线程中的 accepted answer 和 Peter's answer 仍然有效。没有更简单的方法可以通过 cleanup() 方法找出测试是否失败。
无论如何,它并不像看起来那么复杂,因为您只需设置一次,然后它就可以工作了。由于您没有提到您想要登录cleanup() 的确切内容,我将进行一些推测。出于演示目的,我只是记录了从规范上下文中检索到的功能方法名称,以及发生的错误的类(以免两次打印整个花哨的 Spock 错误消息),从注册的运行侦听器中检索到我将在这里介绍全局扩展。
全球 Spock 扩展:
该扩展注册了一个运行监听器,它在发生测试错误时记录错误信息。在每个功能或迭代开始时(对于具有 where: 块的功能),最后记录的错误被清除,以免渗入下一个功能/迭代。
package de.scrum_master.testing.extension
import org.spockframework.runtime.AbstractRunListener
import org.spockframework.runtime.extension.AbstractGlobalExtension
import org.spockframework.runtime.model.ErrorInfo
import org.spockframework.runtime.model.IterationInfo
import org.spockframework.runtime.model.SpecInfo
class TestResultExtension extends AbstractGlobalExtension {
@Override
void visitSpec(SpecInfo spec) {
spec.addListener(new ErrorListener())
}
static class ErrorListener extends AbstractRunListener {
ErrorInfo errorInfo
@Override
void beforeIteration(IterationInfo iteration) {
errorInfo = null
}
@Override
void error(ErrorInfo error) {
errorInfo = error
}
}
}
如何注册 Spock 扩展:
您还需要将文件META-INF/services/org.spockframework.runtime.extension.IGlobalExtension 添加到您的测试资源中才能注册扩展。该文件仅包含以下内容:
de.scrum_master.testing.extension.TestResultExtension
顺便说一句,这不是 Spock 或 Groovy 的东西,而是称为 service providers 的标准 Java SE 功能。
使用扩展的示例测试:
这个测试非常愚蠢,但它展示了它如何适用于普通方法和带有where: 块的方法,无论有没有@Unroll。
package de.scrum_master.testing.extension
import spock.lang.Specification
import spock.lang.Unroll
class TestFailureReportingTest extends Specification {
def "failing normal feature"() {
expect:
0 == 1
}
def "passing normal feature"() {
expect:
0 == 0
}
def "parametrised feature"() {
expect:
a == b
where:
a << [2, 4, 6]
b << [3, 5, 6]
}
@Unroll
def "unrolled feature with #a/#b"() {
expect:
a == b
where:
a << [6, 8, 0]
b << [7, 9, 0]
}
def cleanup() {
specificationContext.currentSpec.listeners
.findAll { it instanceof TestResultExtension.ErrorListener }
.each {
def errorInfo = (it as TestResultExtension.ErrorListener).errorInfo
if (errorInfo)
println "Test failure in feature '${specificationContext.currentIteration.name}', " +
"exception class ${errorInfo.exception.class.simpleName}"
else
println "Test passed in feature '${specificationContext.currentIteration.name}'"
}
}
}
控制台日志(省略实际错误)将是:
Test failure in feature 'failing normal feature', exception class ConditionNotSatisfiedError
Test passed in feature 'passing normal feature'
Test failure in feature 'parametrised feature', exception class ConditionNotSatisfiedError
Test failure in feature 'parametrised feature', exception class ConditionNotSatisfiedError
Test passed in feature 'parametrised feature'
Test failure in feature 'unrolled feature with 6/7', exception class ConditionNotSatisfiedError
Test failure in feature 'unrolled feature with 8/9', exception class ConditionNotSatisfiedError
Test passed in feature 'unrolled feature with 0/0'
P.S.:错误信息在功能方法内的cleanup: 块中不可用,因为扩展仅在包括该块在内的整个功能/迭代完成运行后才会启动。因此,您确实必须使用 cleanup() 方法,但无论如何您都希望这样做,它可以避免代码重复。
P.P.S.:当然,您也可以只在方法拦截器中进行通用日志记录,然后跳过整个 cleanup() 方法。但是,您不再可以使您的日志输出特定于测试,并且它将用于所有您的测试,而不仅仅是您选择的测试 - 当然除非您对包或规范名称过滤器进行硬编码直接进入拦截器或确保Spock启动时拦截器读取相应的配置文件。