When Spock's @Shared annotation should be preferred over a static field?

Viewed 23790

There is not much to add, the whole question is in the title.

Consider these two instances of class Foo used in a Spock specification.

@Shared Foo foo1 = new Foo()

static Foo foo2 = new Foo()

Overall, I know the idea behind @Shared annotation but I guess it's better to use language features, which in this case would be static field.

Are there any specific cases in which one should preferred over the other or it's rather a matter of taste?

4 Answers

As a more exhaustive approach, here is a sample test with outputs:

@Unroll
class BasicSpec extends Specification {
    
    int initializedVariable
    
    int globalVariable = 200
    
    static int STATIC_VARIABLE = 300
    
    @Shared
    int sharedVariable = 400
    
    void setup() {
        initializedVariable = 100
    }
    
    void 'no changes'() {
        expect:
            printVariables()
            /*
            initializedVariable: 100
            globalVariable: 200
            STATIC_VARIABLE: 300
            sharedVariable: 400
             */
    }
    
    void 'change values'() {
        setup:
            initializedVariable = 1100
            globalVariable = 1200
            STATIC_VARIABLE = 1300
            sharedVariable = 1400
        
        expect:
            printVariables()
            /*
            initializedVariable: 1100
            globalVariable: 1200
            STATIC_VARIABLE: 1300
            sharedVariable: 1400
             */
    }
    
    void 'print values again'() {
        expect:
            printVariables()
            /*
            initializedVariable: 100
            globalVariable: 200
            STATIC_VARIABLE: 1300
            sharedVariable: 1400
             */
    }
    
    private void printVariables() {
        println "initializedVariable: $initializedVariable"
        println "globalVariable: $globalVariable"
        println "STATIC_VARIABLE: $STATIC_VARIABLE"
        println "sharedVariable: $sharedVariable\n"
    }
}

The surprising thing to me is that both the variable in the class' setup() method AS WELL as the global, instanced variable get reset on each test (presumably because the class is re-instantiated for each test case). Meanwhile, the static and the @Shared variable work as expected. As a result, the latter two are also able to be accessed in where clauses, which are run before some of the other ones that are listed prior in each test case.

Static fields should only be used for constants. Otherwise shared fields are preferable, because their semantics with respect to sharing are more well-defined.

Related