webentwicklung-frage-antwort-db.com.de

Wann sollte die @Shared-Annotation von Spock einem statischen Feld vorgezogen werden?

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?

14
topr

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

13
kazanaki

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.

9
Valya

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.

1
Igor

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.

0
jun zhou