2016-04-11 6 views
5

In einer Spock Spezifikation jede Linie in erwarten: oder dann: Block ausgewertet wird und behauptet als boolean, es sei denn, es Unterschrift mit Rückgabetyp void hat.Gibt es eine Möglichkeit, zu verhindern, dass Geb Null von void-Methoden zurückgibt?

Ich habe bemerkt, dass es für Methoden wie void für jede Klasse von Navigator vererben erklärt etwas seltsam los ist (zum Beispiel Page oder Module Klassen).

Lassen Sie sagen, wir solches Beispiel haben:

class NavigationSpec extends GebSpec { 

    def 'Collections page has a right header'() { 

     when: 
      to CollectionsPage 

     then: 
      hasHeaderText('Collections') 
    } 
} 

Die hasHeaderText() Methode wird innerhalb CollectionsPage Klasse wie folgt definiert:

class CollectionsPage extends Page { 

    static url = 'movies/collections' 

    void hasHeaderText(String expectedText) { 
     assert true 
    } 
} 

Absichtlich ich behaupten nur true es über so sollte es nie Scheitern. Auch wenn es nicht mit einem Fehler:

Condition not satisfied: 

hasHeaderText('Collections') 
| 
null 

Wie und warum ein void Methodenaufruf Ergebnis als null ausgewertet wird?

Ich weiß, wie man es "repariert". Es reicht, den Rückgabetyp der Methode als boolean zu deklarieren und true zurückzugeben. Dies ist zwar hässlich, wie folgend alle behauptet sonst unnötig return true hat wie hinzugefügt werden:

boolean hasHeaderText(String expectedText) { 
    assert header.text() == expectedText 
    return true 
} 

Dies führt allerdings nur Rauschen. Gibt es eine Möglichkeit, Geb zu verhindern, null von void Methoden zurückzugeben?

Ich bin natürlich bewusst, dass dieser spezielle Fall wie gehen könnte:

boolean hasHeaderText(String expectedText) { 
    header.text() == expectedText` 
} 

Das die Kuriosität des verlorenen void Rückgabetypen nicht erklären, nicht zu erwähnen wir sinnvoll Assertion Fehlermeldung verlieren mit solcher Ansatz.

Antwort

4

Es gehört zur Groovy-Sprache, dass jede Methode einen Wert zurückgibt. Dadurch kann jede Methode in Ausdrücken oder als Lambdas verwendet werden.

Alle Methoden, die void deklariert sind, geben null zurück.

Wenn Sie keine Rückgabeanweisung explizit haben, wird das Ergebnis des letzten Ausdrucks in Ihrer Methode zurückgegeben.

Sie können an der Bytecode aussehen ... auch wenn Sie einen Rückgabetyp erklären, dass Sie nicht wirklich etwas wie Groovy zurückkehren benötigen, standardmäßig null zurück:

// returns null 
String callMe() { } 

static void main(args) { 
    def x = callMe() 
    assert x == null 
    println "OK!" 
} 

Da Spock wird assert alles im then Block, der keine einfache Zuweisung ist, müssen Sie vermeiden, etwas anderes als Boolean Assertions im then Block zu tun. Selbst wenn man eine Variable zuweist, obwohl sie erlaubt ist, sollte man sie vermeiden ... Es ist schwierig, die Tests sauber und klar zu halten, und die Einhaltung dieser Richtlinien wird auf lange Sicht wirklich für dich funktionieren, nicht gegen dich.

Also, die richtige Art und Weise die Behauptung Sie wollen zu schreiben, ist Ihre Methode eine boolean zurückgeben zu machen:

boolean hasHeaderText(String expectedText) { 
    header.text() == expectedText 
} 

und verwenden Sie es in der then Block:

then: 'The header has the expected text #expectedText' 
hasHeaderText expectedText 

sieht ziemlich gut, wenn du fragst mich.

EDIT

Ich habe bemerkt, dass Groovy/Spock tatsächlich nicht das Ergebnis eine normalen void-Methode behauptet sogar im then Block ... Was wahrscheinlich ist, dass Sie ist los keine normale Void-Methode, Sie scheinen eine dynamische Methode von CollectionsPage aufrufen (ich denke, das ist Gebs Magie im Spiel), was bedeutet, dass wahrscheinlich, der Spock AST Transformer hat nicht die Möglichkeit, die Signatur zu überprüfen von der Methode, die Sie aufrufen, also nimmt es richtig an, dass es das Ergebnis bestätigen muss. .. so sieht es zumindest aus.

+0

Danke für Ihre Antwort. Ich bin mir der Dinge bewusst, die du geschrieben hast, besonders den Teil, in dem du Notizen bearbeitest. In der Tat sollte die void-Methode nicht als assert in spocks then block ausgewertet werden. Pages Methode wird als normaler Weg deklariert, aber das ist auch meine Annahme, dass Geb etwas AST-Magie damit macht und damit den Vertrag bricht. Die Verwendung von Booleans mit 'expectedText' außerhalb der Methode ist weit entfernt von dem, was ich erreichen möchte. Power-Assert-ausgearbeitete Fehlermeldungen gehen verloren (denken Sie zB daran, zwei Karten zu vergleichen) und der Text muss jedes Mal wiederholt werden, wenn die Methode verwendet wird (DRY). Ich halte das für einen Geb-Bug – topr

3

@Renato ist im bearbeiteten Teil seiner Antwort korrekt - Ihr Aufruf an eine Void-Methode wird von Spock bestätigt, weil es ein dynamischer Aufruf ist und Spock nicht herausfinden kann, dass Sie eine Void-Methode aufrufen und eifrig behauptet der Anruf. Wenn Sie Ihren Code geändert haben in:

class NavigationSpec extends GebSpec { 

    def 'Collections page has a right header'() { 
     when: 
      CollectionsPage collectionsPage = to CollectionsPage 

     then: 
      collectionsPage.hasHeaderText('Collections') 
    } 

} 

dann wird es nicht geltend gemacht werden.

+0

Danke für die Antwort. Ich war ziemlich sicher, dass dies wegen der Dynamik des Anrufs ist. Seltsamerweise habe ich es nicht verstanden, es funktioniert gut, wenn es direkt auf dem besitzenden Objekt aufgerufen wird. Übrigens, welche Antwort sollte ich jetzt akzeptieren? @Renato war zuerst, während deins mehr Details gibt :) – topr

+1

Wahrscheinlich verdient @Renato eine Annahme, da seine Antwort die erste richtige war. :) – erdi

+0

Du bist zu bescheiden. @Renato Antwort war nur eine generische Bestätigung meiner eigenen Annahmen, dass es "eine dynamische Magie" ist, aber es gab weder Details darüber, was vor sich geht noch eine Lösung. Also akzeptiere ich deine. Ich hoffe, er macht nichts aus ... – topr