Es gibt nicht viel hinzuzufügen, die ganze Frage steht im Titel.
Betrachten Sie diese beiden Instanzen der Klasse Foo, die in einer Spock-Spezifikation verwendet werden.
@Shared Foo foo1 = new Foo()
static Foo foo2 = new Foo()
Insgesamt kenne ich die Idee hinter der @Shared
-Annotation, aber ich denke, es ist besser, Sprachfeatures zu verwenden, die in diesem Fall static
-Feld wären.
Gibt es konkrete Fälle, in denen man den anderen bevorzugen sollte oder eher Geschmackssache?
Bei Spock dreht sich alles um Ausdrucksstärke und Klarheit.
Static ist ein Java-Schlüsselwort, das nur das Intern der Klasse zeigt (dass dieses Feld für alle Instanzen gleich ist).
@Shared ist ein Spock-Feature, das dem Leser sagt, dass diese Variable für alle Feature-Methoden gleich ist. Es ist eine Anweisung speziell für den Gerätetest und macht den Gerätetest für den Leser klarer.
Dasselbe gilt für die Hauptspockblöcke. Wenn Sie darüber nachdenken, ändern sie nichts an dem 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
}
Beide Unit-Tests machen technisch genau dasselbe. Die zweite zeigt jedoch deutlicher die Absicht. Die when: und then: -Labels tun mit dem Code nichts anderes als die Absicht zu klären.
Zusammenfassend: @Shared macht den Test lesbarer. (Siehe auch @Ausgabe , @Title usw., sie existieren zu demselben Zweck.)
Im Gegensatz zu JUnit, wo Sie die Feldvariable static deklarieren und ihr einen Wert zuweisen müssen
@BeforeClass
public static void setupClass()
es wurde also nur einmal pro Testsuite (nicht für jede Methode) initialisiert. In Spock können Sie die Instanzfeldvariable verwenden und mit @Shared
versehen.
Betrachten Sie das folgende Beispiel:
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}"
}
}
Wenn Sie SubclassSpec ausführen, erhalten Sie folgende Ausgabe:
test one, shared: I came from SubclassSpec
test two, shared: I came from SubclassSpec
They've got me!
Ich kann die Druckreihenfolge nicht erklären, aber das liegt an AST.
Ein erschöpfenderer Ansatz ist ein Beispieltest mit Ergebnissen:
@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"
}
}
Das Überraschende für mich ist, dass sowohl die Variable in der setup()
-Methode der Klasse AS WELL als auch die globale, instanzierte Variable bei jedem Test zurückgesetzt wird (vermutlich, weil die Klasse für jeden Testfall erneut instanziiert wird). In der Zwischenzeit arbeiten die Variable static
und @Shared
wie erwartet. Auf die beiden letztgenannten kann daher auch in where
-Klauseln zugegriffen werden, die vor einigen der anderen ausgeführt werden, die in jedem Testfall zuvor aufgeführt wurden.
Statische Felder sollten nur für Konstanten verwendet werden. Ansonsten sind gemeinsam genutzte Felder vorzuziehen, da ihre Semantik in Bezug auf das Teilen klarer definiert ist.