Search code examples
spock

Have Spock fail a data-driven feature if an iteration fails


Is there a way to do the equivalent of @Stepwise's failure behavior for a single feature? We have some integration tests that are set up such that setupSpec() kicks off a Kafka process, and then the actual test checks that each step happened. If step 3 failed, there's no reason to bother checking subsequent steps.


Solution

  • There is no built-in way to do this, but assuming you are using a recent 2.x Spock version and not 1.3 or so, a relatively simple annotation-driven Spock extension can do the trick for you.

    package de.scrum_master.stackoverflow.q71414311
    
    import org.spockframework.runtime.extension.ExtensionAnnotation
    
    import java.lang.annotation.ElementType
    import java.lang.annotation.Retention
    import java.lang.annotation.RetentionPolicy
    import java.lang.annotation.Target
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    @ExtensionAnnotation(StepwiseIterationsExtension)
    @interface StepwiseIterations {}
    
    package de.scrum_master.stackoverflow.q71414311
    
    import org.spockframework.runtime.extension.IAnnotationDrivenExtension
    import org.spockframework.runtime.model.FeatureInfo
    import org.spockframework.runtime.model.parallel.ExecutionMode
    
    class StepwiseIterationsExtension implements IAnnotationDrivenExtension<StepwiseIterations> {
      @Override
      void visitFeatureAnnotation(StepwiseIterations annotation, FeatureInfo feature) {
        // Disable parallel iteration execution for @StepwiseIterations feature,
        // similarly to how @Stepwise disables it for the whole specification
        feature.setExecutionMode(ExecutionMode.SAME_THREAD)
    
        // If an error occurs in this feature, skip remaining iterations
        feature.getFeatureMethod().addInterceptor({ invocation ->
          try {
            invocation.proceed()
          }
          catch (Throwable t) {
            invocation.getFeature().skip("skipping subsequent iterations after failure")
            throw t
          }
        })
      }
    }
    

    Add this to your code base, annotate your iterated test with @StepwiseIterations and run it. I think the result is exactly what you are looking for.

    In Spock 1.3, an similar, but more complex extension would also be possible.

    I also want to express my special thanks to Leonard Brünings, Spock maintainer and boundless source of knowledge. I had a more complex version of this extension in place, but after discussing with him, it evolved into this tiny, elegant solution we are seeing here.


    FYI, there is a pre-existing Spock issue #1008 requesting this feature. I created pull request #1442 which adds this capability to @Stepwise. So hopefully in the future we do not need an extra annotation and extra extension anymore.