web-dev-qa-db-fra.com

Quand l'annotation @Shared de Spock devrait-elle être préférée à un champ statique?

Il n'y a pas grand chose à ajouter, toute la question est dans le titre.

Considérez ces deux instances de la classe Foo utilisées dans une spécification de Spock.

@Shared Foo foo1 = new Foo()

static Foo foo2 = new Foo()

Dans l’ensemble, je connais l’idée qui sous-tend l’annotation @Shared, mais j’imagine qu’il est préférable d’utiliser des fonctionnalités de langage, qui dans ce cas seraient static field.

Existe-t-il des cas spécifiques dans lesquels on devrait préférer l'un à l'autre ou est-ce plutôt une question de goût?

14
topr

Spock est tout au sujet de expressivité et clarté.

Static est un mot-clé Java indiquant uniquement les éléments internes de la classe (ce champ est identique pour toutes les instances).

@Shared est une fonction de Spock qui indique au lecteur que cette variable est la même pour toutes les méthodes. C'est une instruction spécifique pour le test unitaire et rend le test unitaire plus clair pour le lecteur.

La même chose peut être dite pour les blocs principaux de Spock. Si vous y réfléchissez, ils ne changent rien au code.

public void myScenario(){
  int a = 2 + 3;
  assertEquals(5,a);
}

public void "simple addition scenario"(){
  when: "I add two numbers"
    int a = 2 +3

  then: "I expect the correct result"
  a == 5
}

Les deux tests unitaires font exactement la même chose techniquement. La seconde montre toutefois plus clairement l'intention. Les étiquettes quand: et alors: ne font rien d'autre avec le code que la clarification de son intention.

Donc pour résumer, @Shared rend le test plus lisible. (Voir aussi @Issue , @Titre etc., ils existent dans le même but)

13
kazanaki

Contrairement à JUnit, où vous devez déclarer la variable de champ static et lui attribuer une valeur dans

@BeforeClass
public static void setupClass()

il n'a donc été initialisé qu'une fois par suite de tests (et non par chaque méthode). Dans Spock, vous pouvez utiliser une variable de champ d'instance et l'annoter avec @Shared.

Prenons l'exemple suivant:

class SharedTestSpec extends spock.lang.Specification {

    @Shared
    def shared = shared()

    def shared() {
        "I came from ${this.class.simpleName}"
    }

    def 'Test one'() {
        given:
            println("test one, shared: $shared")
        expect: true
    }

    def 'Test two'() {
        given:
            println("test two, shared: $shared")
        expect: true

    }
}

class SubclassSpec extends SharedTestSpec {

    @Override
    def shared() {
        println("They've got me!")
        "I came from ${this.class.simpleName}"
    }
}

L'exécution de SubclassSpec vous donne la sortie suivante:

test one, shared: I came from SubclassSpec
test two, shared: I came from SubclassSpec
They've got me!

Je ne peux pas expliquer la commande d'impression, mais cela est dû à AST.

9
Valya

En guise d’approche plus exhaustive, voici un exemple de test avec résultats:

@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"
    }
}

Ce qui me surprend, c’est que la variable de la méthode setup() de la classe, ainsi que la variable instanciée globale, soient réinitialisées à chaque test (probablement parce que la classe est ré-instanciée pour chaque cas de test). Pendant ce temps, les variables static et @Shared fonctionnent comme prévu. Par conséquent, il est également possible d'accéder à ces deux derniers dans les clauses where, qui sont exécutées avant certaines des autres, répertoriées précédemment dans chaque cas de test.

1
Igor