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?
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)
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.
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.