2016-03-10 5 views
11

Es gibt nicht viel hinzuzufügen, die ganze Frage ist im Titel.Wenn Spocks @ Shared-Annotation einem statischen Feld vorgezogen werden sollte?

Betrachten Sie diese beiden Instanzen der Klasse Foo in einer Spock-Spezifikation verwendet.

@Shared Foo foo1 = new Foo() 

static Foo foo2 = new Foo() 

Insgesamt weiß, dass ich die Idee hinter @Shared Anmerkung aber ich denke, es ist besser, Sprachfunktionen zu verwenden, die in diesem Fall static Feld sein würde.

Gibt es spezielle Fälle, in denen man dem anderen den Vorzug geben sollte oder eher eine Frage des Geschmacks?

+1

Afaik sind sie effektiv die gleiche funktional, aber '@ Shared' besser zeigt Ihre Absicht –

Antwort

6

Spock ist alles über Ausdruckskraft und Klarheit.

Static ist ein Java-Schlüsselwort, das nur die Interna der Klasse zeigt (dass dieses Feld das gleiche für alle Fälle ist)

@Shared ist eine Spock-Funktion, dass dieser Variable den Leser sagt ist für alle Feature-Methoden gleich. Es ist eine Anweisung speziell für den Komponententest und macht den Komponententest für den Leser klarer.

Das gleiche gilt für die wichtigsten Spock-Blöcke. Wenn Sie darüber nachdenken, ändern sie nichts am 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 Komponententests machen genau dasselbe technisch. Die zweite zeigt jedoch deutlicher die Absicht. Die wenn: und dann: Etiketten tun nicht wirklich etwas mit dem Code anders als Klärung seiner Absicht.

Also zusammenzufassen @Shared macht den Test lesbarer. (Siehe auch @Issue, @Title usw., existieren sie für den gleichen Zweck)

+0

Nun, es gibt einen kleinen Unterschied in haben und nicht 'dann' blockieren. Asserts sind implizit auf jede nicht-void-Linie in einem solchen Block. Aber vereinbart, der meiste Wert kommt in der Lesbarkeit. Danke für die Antwort, ich stimme es hoch, werde aber noch etwas warten, um zu sehen, ob noch etwas erscheint. Ich bin gespannt, ob es irgendeinen anderen 'syntaktischen Zucker'-Grund gibt, @Shared gegenüber statischem (oder gegenüberliegendem) vorzuziehen. – topr

5

Im Gegensatz zu JUnit, wo Sie Feld deklarieren müssen variable statische und weisen Wert, um es in

@BeforeClass 
public static void setupClass() 

so wurde es nur einmal pro Testsuite (nicht jede Methode) initialisiert, in Spock können Sie die Instanzfeldvariable verwenden und sie mit @Shared annotieren.

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

SubclassSpec Laufen gibt Ihnen die folgende Ausgabe:

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

Kann den Druckauftrag, wenn auch nicht erklären, aber das ist aufgrund AST.

+0

Interessant, danke. Um beide Antworten zusammenzufassen: '@ Shared' macht die Spezifikation lesbarer und ermöglicht den Vorteil einer Instanz basierten Methoden (wie Überschreiben). – topr

0

Als erschöpfendere Ansatz, hier ist ein Probe-Test mit Ausgängen:

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

Die überraschende Sache für mich ist, dass sowohl die Variablen in der Klasse setup() Verfahren sowie der globale, instanzierte Variable erhalten bei jedem Test zurückgesetzt (vermutlich weil die Klasse für jeden Testfall erneut instanziiert wird). Unterdessen arbeiten die static und die @Shared Variable wie erwartet. Als Ergebnis können die letzten beiden auch in where-Klauseln zugegriffen werden, die vor einigen der anderen ausgeführt werden, die in jedem Testfall aufgelistet sind.

+0

Instanzvariablen werden für jeden '@ Test'-Fall instanziiert, kein Wunder, das gleiche gilt für JUnit. Kannst du den letzten Satz ausarbeiten? Ich verstehe es nicht. – Valya