Annotation Interface Togglz


@Retention(RUNTIME) @Target({TYPE,METHOD}) @Inherited public @interface Togglz
Creates a TestFeatureManager for the test.

Allows the user to control the state of a Feature for a test or specification. It can only be used to manage one feature enum at a time, as the TestFeatureManager doesn't support multiple features.

Parallel Execution Support

This extension supports Spock's parallel execution capability. Every specification and test annotated with @Togglz will acquire READ_WRITE lock for the key TogglzExtension.TOGGLZ_FEATURE_RESOURCE.

Where to apply

Can be applied on individual tests and on the specification.

When applied on an individual test it will only affect that test.

When applied on an specification it will behave as if every test was annotated with the same annotation.

If both test and specification is annotated, then both will be merged, and the feature annotation will override the specification annotation on conflicts.

Here are some examples:

Annotation on Specification Annotation on Test Result
@Togglz(allEnabled = MyFeature) - allEnabled = MyFeature
- @Togglz(allDisabled = MyFeature) allDisabled = MyFeature
@Togglz(allEnabled = MyFeature) @Togglz(allDisabled = MyFeature) allDisabled = MyFeature
@Togglz(allEnabled = MyFeature) @Togglz(disable = {[MyFeature.One]}) allEnabled = MyFeature, disable = {[MyFeature.One]})
@Togglz(allEnabled = MyFeature) @Togglz(allDisabled = MyFeature, enable = {[MyFeature.One]}) allDisabled = MyFeature, enable = {[MyFeature.One]})

Enabling/disabling individual features

You always have to have either allEnabled or allDisabled defined for a test. You can inherit the value from the specification (see the Where to apply chapter).

If you have used allDisabled then you can enable individual features using the enable setting. The same applies for allEnabled and disabled.

Note: enable/disabled expect a closure that returns a list, not a list directly.

Here are some examples:

 @Togglz(allDisabled = MyFeature)
 class MyTest extends Specification {
     def "test allDisabled"() {
         expect:
         !MyFeature.ONE.active
         !MyFeature.TWO.active
     }

     @Togglz(enable = {[MyFeature.One]})
     def "enable feature one"() {
         expect:
         MyFeature.ONE.active
         !MyFeature.TWO.active
     }

     @Togglz(enable = {[MyFeature.TWO]})
     def "enable feature one"() {
         expect:
         !MyFeature.ONE.active
         MyFeature.TWO.active
     }
 }
 

Injecting TestFeatureManager into a test

You can declare TestFeatureManager as a parameter to any test that is either directly annotated with @Togglz or it's Specification is annotated with it.

Here are some examples:

 @Togglz(allDisabled = MyFeature)
 class MyTest extends Specification {

      def "injection in non data-driven feature"(TestFeatureManager testFeatureManager) {
          expect:
          MyFeatures.values().every { !it.active }

          when:
          testFeatureManager.enable(MyFeatures.ONE)

          then:
          MyFeatures.ONE.active
      }

      def "data-driven disabled"(MyFeatures feature, TestFeatureManager testFeatureManager) {
          expect:
          MyFeatures.values().every { !it.active }

          when:
          testFeatureManager.enable(feature)

          then:
          feature.active

          where:
          feature << MyFeatures.values()
      }
 }
 

Advanced usage

As enable/disabled use a closure, you can add logic to control which feature is enabled/disabled. The closure gets PreconditionContext as parameter so you can use it to control which feature is returned.

Use this feature with care!

Here is an example:

 @Togglz(allDisabled = MyFeatures,
     enable = { PreconditionContext pc -> pc.os.windows ? [MyFeatures.ONE] : [MyFeatures.TWO] })
 def "all disabled with individual enabled using PreconditionContext"() {
     given:
     def os = OperatingSystem.getCurrent()

     expect:
     MyFeatures.ONE.active == os.windows
     MyFeatures.TWO.active == !os.windows
     !MyFeatures.THREE.active
 }
 
  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    static class 
    Marker class to indicate that the field has the default value.
  • Optional Element Summary

    Optional Elements
    Modifier and Type
    Optional Element
    Description
    Class<? extends org.togglz.core.Feature>
    Feature class that should have every feature disabled.
    Class<? extends org.togglz.core.Feature>
    Feature class that should have every feature enabled.
    Class<? extends groovy.lang.Closure<List<? extends org.togglz.core.Feature>>>
    The inverse of enable() It cannot be combined with allDisabled(). It is mutually exclusive with enable().
    Class<? extends groovy.lang.Closure<List<? extends org.togglz.core.Feature>>>
    Can be used in conjunction with allDisabled() to enable individual features again.
  • Element Details

    • allEnabled

      Class<? extends org.togglz.core.Feature> allEnabled
      Feature class that should have every feature enabled.

      Example Usage:

      @Togglz(allEnable = MyFeature)

      It is mutually exclusive with allDisabled().

      Default:
      org.togglz.spock.Togglz.None.class
    • allDisabled

      Class<? extends org.togglz.core.Feature> allDisabled
      Feature class that should have every feature disabled.

      It is mutually exclusive with allEnabled().

      Default:
      org.togglz.spock.Togglz.None.class
    • enable

      Class<? extends groovy.lang.Closure<List<? extends org.togglz.core.Feature>>> enable
      Can be used in conjunction with allDisabled() to enable individual features again.

      Define a closure that returns a list of features to enable.

      Example Usage:

      @Togglz(allDisable = MyFeature, enable = {[MyFeature.ONE]})

      Default:
      org.togglz.spock.Togglz.None.class
    • disable

      Class<? extends groovy.lang.Closure<List<? extends org.togglz.core.Feature>>> disable
      The inverse of enable()
      Default:
      org.togglz.spock.Togglz.None.class