从Spock测试中动态排除类

时间:2014-08-05 11:57:34

标签: unit-testing groovy configuration spock

我们希望从Spock测试中排除一组特定的测试类,具体取决于是否设置了某些系统属性。现在我们得到了一些代码:

runner {
    // skip all slow tests automatically unless test.include.slow=true
    if (!Boolean.getBoolean('test.include.slow')) { exclude Slow }

    // skip all api tests unless test.include.api=true
    if (!Boolean.getBoolean('test.include.api')) { exclude ApiTest }
}

在我们的SpockConfig.groovy中。问题是,第二次排除调用实际上会覆盖第一次调用中定义的排除。我们还尝试构建一个类数组,并将其处理为exclude函数,如下所示:

runner {

    Class[] toExclude = []

    // skip all slow tests automatically unless test.include.slow=true
    if (!Boolean.getBoolean('test.include.slow')) { toExclude << Slow }

    // skip all api tests unless test.include.api=true
    if (!Boolean.getBoolean('test.include.api')) { toExclude << ApiTest }

    exclude toExclude
}

然而,这产生了非常奇怪的例外:

java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at com.intellij.junit4.IdeaSuite.getDescription(IdeaSuite.java:55)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:43)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:211)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:67)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
Caused by: groovy.lang.MissingMethodException: No signature of method: SpockConfig.runner() is applicable for argument types: (SpockConfig$_run_closure1) values: [SpockConfig$_run_closure1@66d33a32]
Possible solutions: run(), run(), run(java.io.File, [Ljava.lang.String;), use([Ljava.lang.Object;)
    at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:55)
    at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:78)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:49)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:133)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141)
    at SpockConfig.run(SpockConfig.groovy:4)
    at org.spockframework.builder.DelegatingScriptBlueprint.evaluate(DelegatingScriptBlueprint.java:33)
    at org.spockframework.builder.Sculpturer.$form(Sculpturer.java:32)
    at org.spockframework.builder.GestaltBuilder.build(GestaltBuilder.java:19)
    at org.spockframework.runtime.ConfigurationBuilder.build(ConfigurationBuilder.java:30)
    at org.spockframework.runtime.RunContext.<init>(RunContext.java:54)
    at org.spockframework.runtime.RunContext.createBottomContext(RunContext.java:150)
    at org.spockframework.runtime.RunContext.get(RunContext.java:130)
    at org.spockframework.runtime.Sputnik.runExtensionsIfNecessary(Sputnik.java:86)
    at org.spockframework.runtime.Sputnik.getDescription(Sputnik.java:55)
    at org.junit.runners.Suite.describeChild(Suite.java:123)
    at com.intellij.junit4.IdeaSuite.describeChild(IdeaSuite.java:68)
    at com.intellij.junit4.IdeaSuite.getChildren(IdeaSuite.java:85)
    at org.junit.runners.ParentRunner.getFilteredChildren(ParentRunner.java:351)

那么在SpockConfig.groovy中处理此类排除的正确方法是什么?

3 个答案:

答案 0 :(得分:3)

好的,我们找到了一些解决方案:

runner {
    // skip all slow tests automatically unless test.include.slow=true
    if (!Boolean.getBoolean('test.include.slow')) { exclude.annotations << Slow }

    // skip all api tests unless test.include.api=true
    if (!Boolean.getBoolean('test.include.api')) { exclude.annotations << ApiTest }
}

仍然想知道这是正确的方式还是只是一些糟糕的黑客。

答案 1 :(得分:1)

Spock现在有@IgnoreIf注释来完成这个。

在您要排除的每个测试上方,您可以注释条件,包括系统属性,环境变量和Java版本信息。

@IgnoreIf({ !Boolean.valueOf(properties['test.include.slow']) })
def "run spec if Java system property 'test.include.slow' is true"() {
    expect:
    true
}

答案 2 :(得分:0)

Spock支持JUnit测试规则,它可以提供一种非常干净的方法。例如,您的功能可以使用注释来指定运行时间:

@SlowTest
def "run spec if Java system property 'test.include.slow' is true"() {
    expect:
    true
}

@ApiTest
def "run spec if Java system property 'test.include.api' is true"() {
    expect:
    true
}

首先,您需要创建注释:

<强> SlowTest.java

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SlowTest {
}

<强> ApiTest.java

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiTest {
}

接下来,创建测试规则:

<强> AnnotationsTestRule.java

public class AnnotationsTestRule implements TestRule {

    private final boolean mApiTest;
    private final boolean mSlowTest;

    public AnnotationsTestRule() {
        mApiTest = Boolean.getBoolean("test.include.api")
        mSlowTest = Boolean.getBoolean("test.include.slow")
    }

    @Override
    public Statement apply(Statement base, Description description) {
        return new Statement() {
            @Override
            public void evaluate() throws Throwable {
                if (description.getAnnotation(ApiTest.class) != null && !mApiTest || description.getAnnotation(SlowTest.class) != null && !mSlowTest) {
                    //Skip test when the annotation is present but not the correlating system property
                    return;
                }
                base.evaluate();
            }
        }
    }

}

最后,在每个需要此功能的功能上添加本答案第一部分中提到的注释。对于使用这些规范的规范,您还需要声明测试规则。您只需将此行添加到groovy文件即可完成此操作:

@Rule AnnotationsTestRule mAnnotationsTestRule