diff --git a/docs/extensions.adoc b/docs/extensions.adoc index 45c0709c6f..538d4b220c 100644 --- a/docs/extensions.adoc +++ b/docs/extensions.adoc @@ -351,63 +351,27 @@ With the flag `applyGlobalTimeoutToFixtures` you can control if the global timeo The `@Retry` extensions can be used for flaky integration tests, where remote systems can fail sometimes. By default it retries an iteration `3` times with `0` delay if either an `Exception` or `AssertionError` has been thrown, all this is configurable. In addition, an optional `condition` closure can be used to determine if a feature should be retried. -It also provides special support for data driven features, offering to either retry all iterations or just the failing ones. +In its standard mode it only retries the feature method execution, but this can be changed using `mode` to +also run setup and cleanup on retries. Even in this mode, the retry is only triggered if the feature method is failing +in the expected way. If the setup or cleanup is failing, the test fails immediately. [source,groovy] ---- -class FlakyIntegrationSpec extends Specification { - @Retry - def retry3Times() { ... } - - @Retry(count = 5) - def retry5Times() { ... } - - @Retry(exceptions=[IOException]) - def onlyRetryIOException() { ... } - - @Retry(condition = { failure.message.contains('foo') }) - def onlyRetryIfConditionOnFailureHolds() { ... } - - @Retry(condition = { instance.field != null }) - def onlyRetryIfConditionOnInstanceHolds() { ... } - - @Retry - def retryFailingIterations() { - ... - where: - data << sql.select() - } - - @Retry(mode = Retry.Mode.FEATURE) - def retryWholeFeature() { - ... - where: - data << sql.select() - } - - @Retry(delay = 1000) - def retryAfter1000MsDelay() { ... } -} +include::{sourcedir}/extension/RetryDocSpec.groovy[tag=example-common] +include::{sourcedir}/extension/RetryDocSpec.groovy[tag=example-a] ---- Retries can also be applied to spec classes which has the same effect as applying it to each feature method that isn't -already annotated with {@code Retry}. +already annotated with `@Retry`. [source,groovy] ---- -@Retry -class FlakyIntegrationSpec extends Specification { - def "will be retried with config from class"() { - ... - } - @Retry(count = 5) - def "will be retried using its own config"() { - ... - } -} +include::{sourcedir}/extension/RetryDocSpec.groovy[tag=example-b1] +include::{sourcedir}/extension/RetryDocSpec.groovy[tag=example-common] +include::{sourcedir}/extension/RetryDocSpec.groovy[tag=example-b2] ---- -A {@code @Retry} annotation that is declared on a spec class is applied to all features in all subclasses as well, +A `@Retry` annotation that is declared on a spec class is applied to all features in all subclasses as well, unless a subclass declares its own annotation. If so, the retries defined in the subclass are applied to all feature methods declared in the subclass as well as inherited ones. @@ -416,25 +380,7 @@ Running `BarIntegrationSpec` will execute `inherited` and `bar` with two retries [source,groovy] ---- -@Retry(count = 1) -abstract class AbstractIntegrationSpec extends Specification { - def inherited() { - ... - } -} - -class FooIntegrationSpec extends AbstractIntegrationSpec { - def foo() { - ... - } -} - -@Retry(count = 2) -class BarIntegrationSpec extends AbstractIntegrationSpec { - def bar() { - ... - } -} +include::{sourcedir}/extension/RetryDocSpec.groovy[tag=example-c] ---- Check https://github.com/spockframework/spock/blob/master/spock-specs/src/test/groovy/org/spockframework/smoke/extension/RetryFeatureExtensionSpec.groovy[RetryFeatureExtensionSpec] for more examples. diff --git a/spock-core/src/main/java/spock/lang/Retry.java b/spock-core/src/main/java/spock/lang/Retry.java index 725948b5a7..2f39ae5736 100644 --- a/spock-core/src/main/java/spock/lang/Retry.java +++ b/spock-core/src/main/java/spock/lang/Retry.java @@ -28,7 +28,7 @@ /** - * Retries the given feature if an exception occurs during execution. + * Retries the given feature if an exception occurs during execution of the feature method. * *

Retries can be applied to feature methods and spec classes. Applying it to * a spec class has the same effect as applying it to each feature method that @@ -50,7 +50,7 @@ /** * Configures which types of Exceptions should be retried. * - * Subclasses are included if their parent class is listed. + *

Subclasses are included if their parent class is listed. * * @return array of Exception classes to retry. */ @@ -77,12 +77,12 @@ Class[] skipRetryExceptions() default { * Condition that is evaluated to decide whether the feature should be * retried. * - * The configured closure is called with a delegate of type + *

The configured closure is called with a delegate of type * {@link org.spockframework.runtime.extension.builtin.RetryConditionContext} * which provides access to the current exception and {@code Specification} * instance. * - * The feature is retried if the exception class passes the type check and the + *

The feature is retried if the exception class passes the type check and the * specified condition holds true. If no condition is specified, only the type * check is performed. * @@ -113,12 +113,14 @@ Class[] skipRetryExceptions() default { enum Mode { /** - * Retry the iterations individually. + * Retry only the feature method execution, setup and cleanup are not running on retries. */ ITERATION, /** - * Retry the feature together with the setup and cleanup methods. + * Retry the iteration together with setup and cleanup. + * Even in this mode, the retry is only triggered if the feature method is failing + * in the expected way. If the setup or cleanup is failing, the test fails immediately. */ SETUP_FEATURE_CLEANUP } diff --git a/spock-specs/src/test/groovy/org/spockframework/docs/extension/RetryDocSpec.groovy b/spock-specs/src/test/groovy/org/spockframework/docs/extension/RetryDocSpec.groovy new file mode 100644 index 0000000000..559fac4bb3 --- /dev/null +++ b/spock-specs/src/test/groovy/org/spockframework/docs/extension/RetryDocSpec.groovy @@ -0,0 +1,102 @@ +package org.spockframework.docs.extension + +import groovy.sql.Sql +import spock.lang.Retry +import spock.lang.Shared +import spock.lang.Specification + +abstract +// tag::example-common[] +class FlakyIntegrationSpec extends Specification { +// end::example-common[] + @Shared + def sql = Sql.newInstance("jdbc:h2:mem:", "org.h2.Driver") +} + +class FlakyIntegrationSpecA extends FlakyIntegrationSpec { +// tag::example-a[] + @Retry + def "retry 3 times"() { + expect: true + } + + @Retry(count = 5) + def "retry 5 times"() { + expect: true + } + + @Retry(exceptions = [IOException]) + def "only retry on IOException"() { + expect: true + } + + @Retry(condition = { failure.message.contains('foo') }) + def "only retry if condition on failure holds"() { + expect: true + } + + @Retry(condition = { instance.field != null }) + def "only retry if condition on instance holds"() { + expect: true + } + + @Retry + def "retry failing feature methods"() { + expect: true + + where: + data << sql.execute('') + } + + @Retry(mode = Retry.Mode.SETUP_FEATURE_CLEANUP) + def "retry with setup and cleanup"() { + expect: true + + where: + data << sql.execute('') + } + + @Retry(delay = 1000) + def "retry after 1000 ms delay"() { + expect: true + } +} +// end::example-a[] + +// tag::example-b1[] +@Retry +// end::example-b1[] +class FlakyIntegrationSpecB extends FlakyIntegrationSpec { +// tag::example-b2[] + def "will be retried with config from class"() { + expect: true + } + + @Retry(count = 5) + def "will be retried using its own config"() { + expect: true + } +} +// end::example-b2[] + +// tag::example-c[] +@Retry(count = 1) +abstract class AbstractIntegrationSpec extends Specification { + def inherited() { + expect: true + } +} + +class FooIntegrationSpec extends AbstractIntegrationSpec { + def foo() { + expect: true + } +} + +@Retry(count = 2) +class BarIntegrationSpec extends AbstractIntegrationSpec { + def bar() { + expect: true + } +} +// end::example-c[] diff --git a/spock-specs/src/test/groovy/org/spockframework/smoke/extension/RetryFeatureExtensionSpec.groovy b/spock-specs/src/test/groovy/org/spockframework/smoke/extension/RetryFeatureExtensionSpec.groovy index 188fafd56e..245fee1f81 100644 --- a/spock-specs/src/test/groovy/org/spockframework/smoke/extension/RetryFeatureExtensionSpec.groovy +++ b/spock-specs/src/test/groovy/org/spockframework/smoke/extension/RetryFeatureExtensionSpec.groovy @@ -31,6 +31,7 @@ class RetryFeatureExtensionSpec extends EmbeddedSpecification { static StringBuffer iterationBuffer def setup() { + runner.addClassMemberImport(getClass()) runner.throwFailure = false setupCounter.set(0) cleanupCounter.set(0) @@ -41,15 +42,11 @@ class RetryFeatureExtensionSpec extends EmbeddedSpecification { def "@Retry fails after retries are exhausted"() { when: - def result = runner.runWithImports(""" -import spock.lang.Retry - -class Foo extends Specification { - @Retry - def bar() { - org.spockframework.smoke.extension.RetryFeatureExtensionSpec.featureCounter.incrementAndGet() - expect: false - } + def result = runner.runSpecBody(""" +@Retry +def bar() { + featureCounter.incrementAndGet() + expect: false } """) @@ -67,16 +64,12 @@ class Foo extends Specification { def "@Retry works for normal exceptions"() { when: - def result = runner.runWithImports(""" -import spock.lang.Retry - -class Foo extends Specification { - @Retry - def bar() { - org.spockframework.smoke.extension.RetryFeatureExtensionSpec.featureCounter.incrementAndGet() - expect: - throw new IOException() - } + def result = runner.runSpecBody(""" +@Retry +def bar() { + featureCounter.incrementAndGet() + expect: + throw new IOException() } """) @@ -97,24 +90,20 @@ class Foo extends Specification { withParallelExecution(parallel) when: - def result = runner.runWithImports(""" -import spock.lang.Retry - -class Foo extends Specification { - def setup() { - org.spockframework.smoke.extension.RetryFeatureExtensionSpec.setupCounter.incrementAndGet() - } + def result = runner.runSpecBody(""" +def setup() { + setupCounter.incrementAndGet() +} - @Retry(mode = Retry.Mode.${mode}) - def bar() { - org.spockframework.smoke.extension.RetryFeatureExtensionSpec.featureCounter.incrementAndGet() - expect: - throw new IOException() - } +@Retry(mode = Retry.Mode.${mode}) +def bar() { + featureCounter.incrementAndGet() + expect: + throw new IOException() +} - def cleanup() { - org.spockframework.smoke.extension.RetryFeatureExtensionSpec.cleanupCounter.incrementAndGet() - } +def cleanup() { + cleanupCounter.incrementAndGet() } """) @@ -146,11 +135,11 @@ class Foo extends Specification { when: runner.runSpecBody(""" - @Retry(mode = Retry.Mode.SETUP_FEATURE_CLEANUP) - @ChangeThread - def foo() { - expect: false - } +@Retry(mode = Retry.Mode.SETUP_FEATURE_CLEANUP) +@ChangeThread +def foo() { + expect: false +} """) then: @@ -165,12 +154,12 @@ class Foo extends Specification { when: def result = runner.runSpecBody(""" - @Retry(mode = Retry.Mode.SETUP_FEATURE_CLEANUP) - @ChangeThread - def foo() { - expect: false - where: i << (1..2) - } +@Retry(mode = Retry.Mode.SETUP_FEATURE_CLEANUP) +@ChangeThread +def foo() { + expect: false + where: i << (1..2) +} """) then: @@ -185,26 +174,22 @@ class Foo extends Specification { withParallelExecution(parallel) when: - def result = runner.runWithImports(""" -import spock.lang.Retry - -class Foo extends Specification { - def setup() { - org.spockframework.smoke.extension.RetryFeatureExtensionSpec.setupCounter.incrementAndGet() - } + def result = runner.runSpecBody(""" +def setup() { + setupCounter.incrementAndGet() +} - @Retry(mode = Retry.Mode.${mode}) - def bar() { - org.spockframework.smoke.extension.RetryFeatureExtensionSpec.featureCounter.incrementAndGet() - expect: - throw new IOException() - where: - foo << [1, 2, 3] - } +@Retry(mode = Retry.Mode.${mode}) +def bar() { + featureCounter.incrementAndGet() + expect: + throw new IOException() + where: + foo << [1, 2, 3] +} - def cleanup() { - org.spockframework.smoke.extension.RetryFeatureExtensionSpec.cleanupCounter.incrementAndGet() - } +def cleanup() { + cleanupCounter.incrementAndGet() } """) @@ -231,15 +216,12 @@ class Foo extends Specification { def "@Retry count can be changed"() { when: - def result = runner.runWithImports("""import spock.lang.Retry - -class Foo extends Specification { - @Retry(count = 5) - def bar() { - org.spockframework.smoke.extension.RetryFeatureExtensionSpec.featureCounter.incrementAndGet() - expect: - throw new Exception() - } + def result = runner.runSpecBody(""" +@Retry(count = 5) +def bar() { + featureCounter.incrementAndGet() + expect: + throw new Exception() } """) @@ -257,15 +239,11 @@ class Foo extends Specification { runner.throwFailure = true when: - def result = runner.runWithImports(""" -import spock.lang.Retry - -class Foo extends Specification { - @Retry(exceptions=[IndexOutOfBoundsException]) - def bar() { - expect: - throw new IllegalArgumentException() - } + def result = runner.runSpecBody(""" +@Retry(exceptions=[IndexOutOfBoundsException]) +def bar() { + expect: + throw new IllegalArgumentException() } """) @@ -278,18 +256,14 @@ class Foo extends Specification { runner.throwFailure = true when: - def result = runner.runWithImports(""" -import spock.lang.Retry - -class Foo extends Specification { - @Retry(exceptions=[IndexOutOfBoundsException], mode = Retry.Mode.${mode}) - def bar() { - expect: - throw new IllegalArgumentException() + def result = runner.runSpecBody(""" +@Retry(exceptions=[IndexOutOfBoundsException], mode = Retry.Mode.${mode}) +def bar() { + expect: + throw new IllegalArgumentException() - where: - ignore << [1, 2] - } + where: + ignore << [1, 2] } """) @@ -302,18 +276,14 @@ class Foo extends Specification { def "@Retry works for data driven features"() { when: - def result = runner.runWithImports(""" -import spock.lang.Retry - -class Foo extends Specification { - @Retry - def bar() { - org.spockframework.smoke.extension.RetryFeatureExtensionSpec.featureCounter.incrementAndGet() - expect: test + def result = runner.runSpecBody(""" +@Retry +def bar() { + featureCounter.incrementAndGet() + expect: test - where: - test << [false, false] - } + where: + test << [false, false] } """) @@ -326,18 +296,14 @@ class Foo extends Specification { def "@Retry for @Unroll'ed data driven feature"() { when: - def result = runner.runWithImports(""" -import spock.lang.Retry - -class Foo extends Specification { - @Retry - def bar() { - org.spockframework.smoke.extension.RetryFeatureExtensionSpec.featureCounter.incrementAndGet() - expect: test + def result = runner.runSpecBody(""" +@Retry +def bar() { + featureCounter.incrementAndGet() + expect: test - where: - test << [false, true, true] - } + where: + test << [false, true, true] } """) @@ -350,17 +316,13 @@ class Foo extends Specification { def "@Retry doesn't affect data driven feature where all iterations pass"() { when: - def result = runner.runWithImports(""" -import spock.lang.Retry - -class Foo extends Specification { - @Retry - def bar() { - expect: test + def result = runner.runSpecBody(""" +@Retry +def bar() { + expect: test - where: - test << [true, true, true] - } + where: + test << [true, true, true] } """) @@ -372,17 +334,13 @@ class Foo extends Specification { def "@Retry doesn't affect @Unroll'ed data driven feature where all iterations pass"() { when: - def result = runner.runWithImports(""" -import spock.lang.Retry - -class Foo extends Specification { - @Retry - def bar() { - expect: test + def result = runner.runSpecBody(""" +@Retry +def bar() { + expect: test - where: - test << [true, true, true] - } + where: + test << [true, true, true] } """) @@ -394,15 +352,11 @@ class Foo extends Specification { def "@Retry mode SETUP_FEATURE_CLEANUP ignores previous failures if a retry succeeds"() { when: - def result = runner.runWithImports(""" -import spock.lang.Retry - -class Foo extends Specification { - static int counter - @Retry(mode = Retry.Mode.SETUP_FEATURE_CLEANUP) - def bar() { - expect: counter++ > 0 - } + def result = runner.runSpecBody(""" +static int counter +@Retry(mode = Retry.Mode.SETUP_FEATURE_CLEANUP) +def bar() { + expect: counter++ > 0 } """) @@ -415,18 +369,14 @@ class Foo extends Specification { def "@Retry can add delay between iteration executions"() { when: long start = System.currentTimeMillis() - def result = runner.runWithImports(""" -import spock.lang.Retry - -class Foo extends Specification { - @Retry(delay = 100) - def bar() { - org.spockframework.smoke.extension.RetryFeatureExtensionSpec.featureCounter.incrementAndGet() - expect: test + def result = runner.runSpecBody(""" +@Retry(delay = 100) +def bar() { + featureCounter.incrementAndGet() + expect: test - where: - test << [false, true, true] - } + where: + test << [false, true, true] } """) @@ -442,19 +392,15 @@ class Foo extends Specification { def "@Retry evaluates condition"() { when: - def result = runner.runWithImports(""" -import spock.lang.Retry - -class Foo extends Specification { - @Retry(condition = { failure.message.contains('1') }) - def "bar #message"() { - org.spockframework.smoke.extension.RetryFeatureExtensionSpec.featureCounter.incrementAndGet() - expect: - assert false : message + def result = runner.runSpecBody(""" +@Retry(condition = { failure.message.contains('1') }) +def "bar #message"() { + featureCounter.incrementAndGet() + expect: + assert false : message - where: - message << ['1', '2', '3'] - } + where: + message << ['1', '2', '3'] } """) @@ -467,25 +413,21 @@ class Foo extends Specification { def "@Retry does not evaluate condition if exception type is unexpected"() { when: - def result = runner.runWithImports(""" -import spock.lang.Retry - -class Foo extends Specification { - @Retry(exceptions = IllegalArgumentException, condition = { failure.message.contains('1') }) - def "bar #exceptionClass #message"() { - org.spockframework.smoke.extension.RetryFeatureExtensionSpec.featureCounter.incrementAndGet() - expect: - throw exceptionClass.newInstance(message as String) - - where: - exceptionClass | message - IllegalArgumentException | 1 - IllegalArgumentException | 2 - IllegalStateException | 1 - IllegalStateException | 2 - RuntimeException | 1 - RuntimeException | 2 - } + def result = runner.runSpecBody(""" +@Retry(exceptions = IllegalArgumentException, condition = { failure.message.contains('1') }) +def "bar #exceptionClass #message"() { + featureCounter.incrementAndGet() + expect: + throw exceptionClass.newInstance(message as String) + + where: + exceptionClass | message + IllegalArgumentException | 1 + IllegalArgumentException | 2 + IllegalStateException | 1 + IllegalStateException | 2 + RuntimeException | 1 + RuntimeException | 2 } """) @@ -498,23 +440,19 @@ class Foo extends Specification { def "@Retry provides condition access to Specification instance shared fields"() { when: - def result = runner.runWithImports(""" -import spock.lang.Retry + def result = runner.runSpecBody(""" +@Shared +int value +@Retry(condition = { instance.value == 2 }) +def "bar #input"() { + featureCounter.incrementAndGet() + value = input -class Foo extends Specification { - @Shared - int value - @Retry(condition = { instance.value == 2 }) - def "bar #input"() { - org.spockframework.smoke.extension.RetryFeatureExtensionSpec.featureCounter.incrementAndGet() - value = input + expect: + false - expect: - false - - where: - input << [1, 2, 3] - } + where: + input << [1, 2, 3] } """) @@ -527,22 +465,18 @@ class Foo extends Specification { def "@Retry provides condition access to Specification instance fields"() { when: - def result = runner.runWithImports(""" -import spock.lang.Retry - -class Foo extends Specification { - int value - @Retry(condition = { instance.value == 2 }) - def "bar #input"() { - org.spockframework.smoke.extension.RetryFeatureExtensionSpec.featureCounter.incrementAndGet() - value = input + def result = runner.runSpecBody(""" +int value +@Retry(condition = { instance.value == 2 }) +def "bar #input"() { + featureCounter.incrementAndGet() + value = input - expect: - false + expect: + false - where: - input << [1, 2, 3] - } + where: + input << [1, 2, 3] } """) @@ -555,20 +489,18 @@ class Foo extends Specification { def "@Retry provides condition access to static Specification fields"() { when: - def result = runner.runWithImports(""" -class Foo extends Specification { - static int value - @Retry(condition = { value == 2 }) - def "bar #input"() { - org.spockframework.smoke.extension.RetryFeatureExtensionSpec.featureCounter.incrementAndGet() - value = input + def result = runner.runSpecBody(""" +static int value +@Retry(condition = { value == 2 }) +def "bar #input"() { + featureCounter.incrementAndGet() + value = input - expect: - false + expect: + false - where: - input << [1, 2, 3] - } + where: + input << [1, 2, 3] } """) @@ -582,23 +514,21 @@ class Foo extends Specification { def "@Retry can be declared on a spec class"() { when: def result = runner.runWithImports(""" -import spock.lang.Retry - @Retry class Foo extends Specification { def foo() { - org.spockframework.smoke.extension.RetryFeatureExtensionSpec.featureCounter.incrementAndGet() + featureCounter.incrementAndGet() expect: false } def bar() { - org.spockframework.smoke.extension.RetryFeatureExtensionSpec.featureCounter.incrementAndGet() + featureCounter.incrementAndGet() expect: true } @Retry(count = 1) def baz() { - org.spockframework.smoke.extension.RetryFeatureExtensionSpec.featureCounter.incrementAndGet() + featureCounter.incrementAndGet() expect: false } @@ -615,14 +545,12 @@ class Foo extends Specification { def "@Retry declared on a spec class is inherited"() { when: def result = runner.runWithImports(""" -import spock.lang.Retry - @Retry(count = 1) abstract class Foo extends Specification { } class Bar extends Foo { def bar() { - org.spockframework.smoke.extension.RetryFeatureExtensionSpec.featureCounter.incrementAndGet() + featureCounter.incrementAndGet() expect: false } @@ -639,11 +567,9 @@ class Bar extends Foo { def "@Retry declared on a subclass is applied to all features"() { when: def result = runner.runWithImports(""" -import spock.lang.Retry - abstract class Foo extends Specification { def foo() { - org.spockframework.smoke.extension.RetryFeatureExtensionSpec.featureCounter.incrementAndGet() + featureCounter.incrementAndGet() expect: false } @@ -651,7 +577,7 @@ abstract class Foo extends Specification { @Retry(count = 1) class Bar extends Foo { def bar() { - org.spockframework.smoke.extension.RetryFeatureExtensionSpec.featureCounter.incrementAndGet() + featureCounter.incrementAndGet() expect: false } @@ -668,20 +594,19 @@ class Bar extends Foo { def "@Retry declared on a spec class can be overridden"() { when: def result = runner.runWithImports(""" -import spock.lang.Retry - @Retry(count = 1) abstract class Foo extends Specification { def foo() { - org.spockframework.smoke.extension.RetryFeatureExtensionSpec.featureCounter.incrementAndGet() + featureCounter.incrementAndGet() expect: false } } + @Retry(count = 2) class Bar extends Foo { def bar() { - org.spockframework.smoke.extension.RetryFeatureExtensionSpec.featureCounter.incrementAndGet() + featureCounter.incrementAndGet() expect: false } @@ -697,22 +622,18 @@ class Bar extends Foo { def "@Retry mode SETUP_FEATURE_CLEANUP runs remaining iterations after a failed one for @Unroll'ed features"() { when: - def result = runner.runWithImports(""" -import spock.lang.Retry - -class Foo extends Specification { - static int counter - @Retry(mode = Retry.Mode.SETUP_FEATURE_CLEANUP) - def bar() { - org.spockframework.smoke.extension.RetryFeatureExtensionSpec.iterationBuffer.append(iteration) - expect: - if (iteration == 2) { - throw new RuntimeException() - } - true - where: - iteration << [1, 2, 3, 4] - } + def result = runner.runSpecBody(""" +static int counter +@Retry(mode = Retry.Mode.SETUP_FEATURE_CLEANUP) +def bar() { + iterationBuffer.append(iteration) + expect: + if (iteration == 2) { + throw new RuntimeException() + } + true + where: + iteration << [1, 2, 3, 4] } """) @@ -725,19 +646,15 @@ class Foo extends Specification { def "@Retry mode SETUP_FEATURE_CLEANUP runs all iterations for @Unroll'ed features"() { when: - def result = runner.runWithImports(""" -import spock.lang.Retry - -class Foo extends Specification { - static int counter - @Retry(mode = Retry.Mode.SETUP_FEATURE_CLEANUP) - def bar() { - org.spockframework.smoke.extension.RetryFeatureExtensionSpec.iterationBuffer.append(iteration) - expect: - false - where: - iteration << [1, 2, 3] - } + def result = runner.runSpecBody(""" +static int counter +@Retry(mode = Retry.Mode.SETUP_FEATURE_CLEANUP) +def bar() { + iterationBuffer.append(iteration) + expect: + false + where: + iteration << [1, 2, 3] } """) @@ -750,17 +667,13 @@ class Foo extends Specification { def "@Retry mode SETUP_FEATURE_CLEANUP correctly reports failed iterations for @Unroll'ed features"() { when: - def result = runner.runWithImports(""" -import spock.lang.Retry - -class Foo extends Specification { - @Retry(mode = Retry.Mode.SETUP_FEATURE_CLEANUP) - def bar() { - expect: - result - where: - result << [true, false] - } + def result = runner.runSpecBody(""" +@Retry(mode = Retry.Mode.SETUP_FEATURE_CLEANUP) +def bar() { + expect: + result + where: + result << [true, false] } """) @@ -775,17 +688,15 @@ class Foo extends Specification { } def "@Retry interceptor chains to enclosed interceptors each time"() { - when: - def result = runner.runWithImports(""" -import spock.lang.Retry -import org.spockframework.smoke.extension.CountExecution + given: + runner.addClassImport(CountExecution) -class Foo extends Specification { - @Retry - @CountExecution - def bar(baz) { - expect: false - } + when: + def result = runner.runSpecBody(""" +@Retry +@CountExecution +def bar(baz) { + expect: false } """) @@ -829,7 +740,7 @@ class Foo extends Specification { @Override void visitFeatureAnnotation(CountExecution annotation, FeatureInfo feature) { feature.featureMethod.addInterceptor { invocation -> - org.spockframework.smoke.extension.RetryFeatureExtensionSpec.extensionCounter.incrementAndGet() + extensionCounter.incrementAndGet() invocation.resolveArgument(0, "BAZ") invocation.proceed() }