简短的回答是:这不是 Spock 的工作方式。 setup() 和 setup: 都旨在为参数化测试的每次迭代执行,因为从逻辑上讲,每次迭代都是一个独立的特征方法。我觉得这样挺好的。
伦纳德建议:
你为什么不用setupSpec()?
setupSpec()如果有多个特征方法,这里就不剪了。
您可以编写一个全局或注释驱动的 Spock 扩展,这可以帮助您在特定情况下跳过 setup() 执行。我已经在 this thread 的 Geb 邮件列表中与 Geb 的维护者 Marcin Erdmann 讨论了这两种变体。您可以复制您喜欢的变体的代码并根据您的需要对其进行调整,即,当一个特性方法被自定义 @SkipSetup 注释注释时,您可以扩展注释以将闭包变为评估为条件或只是硬编码跳过所有迭代,但第一个迭代用于假设的@SetupOnce 注释。
或者您可以重构您的测试以使用规范的 Spock,例如仅当 @Shared 变量具有特定值时,才使您的设置代码执行某些操作。我没有看过你的代码,但我的感觉是,如果你认为你需要这个功能,那么你的测试设计就有问题。
更新:我在想这样的事情:
注解驱动的 Spock 扩展:
package de.scrum_master.testing.extension
import org.spockframework.runtime.extension.ExtensionAnnotation
import java.lang.annotation.Retention
import java.lang.annotation.Target
import static java.lang.annotation.ElementType.METHOD
import static java.lang.annotation.RetentionPolicy.RUNTIME
@Retention(RUNTIME)
@Target(METHOD)
@ExtensionAnnotation(SetupOnceExtension)
@interface SetupOnce {}
package de.scrum_master.testing.extension
import org.spockframework.runtime.extension.AbstractMethodInterceptor
import org.spockframework.runtime.extension.IMethodInvocation
class SetupOnceMethodInterceptor extends AbstractMethodInterceptor {
Map<String, Boolean> annotatedFeatures = new HashMap<>()
@Override
void interceptSetupMethod(IMethodInvocation invocation) throws Throwable {
if (annotatedFeatures.containsKey(invocation.feature.name)) {
if (!annotatedFeatures[invocation.feature.name]) {
invocation.proceed()
annotatedFeatures[invocation.feature.name] = true
}
}
else
invocation.proceed()
}
}
package de.scrum_master.testing.extension
import org.spockframework.runtime.extension.AbstractAnnotationDrivenExtension
import org.spockframework.runtime.model.FeatureInfo
class SetupOnceExtension extends AbstractAnnotationDrivenExtension<SetupOnce> {
SetupOnceMethodInterceptor interceptor
@Override
void visitFeatureAnnotation(SetupOnce annotation, FeatureInfo feature) {
if (!interceptor) {
interceptor = new SetupOnceMethodInterceptor()
feature.spec.addSetupInterceptor interceptor
}
interceptor.annotatedFeatures[feature.name] = false
}
}
Spock 规范示例:
package de.scrum_master.testing.extension
import spock.lang.Specification
class SetupOnceTest extends Specification {
def setup() {
println "SetupOnceTest -> setup"
}
def feature1() {
setup:
println "SetupOnceTest -> feature1"
expect:
true
}
@SetupOnce
def feature2() {
setup:
println "SetupOnceTest -> feature2"
expect:
true
}
def feature3() {
setup:
println "SetupOnceTest -> feature3, iteration $count"
expect:
true
where:
count << [1, 2, 3]
}
@SetupOnce
def feature4() {
setup:
println "SetupOnceTest -> feature4, iteration $count"
expect:
true
where:
count << [1, 2, 3]
}
}
控制台日志:
如您所见,对于feature4(),setup() 方法只执行一次。不过,扩展不会影响setup: 块,它们将始终被执行。
SetupOnceTest -> setup
SetupOnceTest -> feature1
SetupOnceTest -> setup
SetupOnceTest -> feature2
SetupOnceTest -> setup
SetupOnceTest -> feature3, iteration 1
SetupOnceTest -> setup
SetupOnceTest -> feature3, iteration 2
SetupOnceTest -> setup
SetupOnceTest -> feature3, iteration 3
SetupOnceTest -> setup
SetupOnceTest -> feature4, iteration 1
SetupOnceTest -> feature4, iteration 2
SetupOnceTest -> feature4, iteration 3