Inkonsistenz zwischen if + else und if - unless

8

Ich hatte heute ein Problem mit der Definition von benutzerdefinierten RSpec-Matcher, die ich gelöst habe, konnte aber keine Gründe dafür erkennen, warum einer der Ansätze funktioniert und der andere nicht, hier ist der Code:

Ansatz 1 - wenn + sonst:

%Vor%

Ansatz 2 - falls gefolgt von

%Vor%

Ich denke, der erste Ansatz ist besser, weil er die Bedingung nur einmal überprüft, aber trotzdem sollte das Ergebnis gleich sein, oder?

Nun, es stellt sich heraus, dass die Tests mit dem ersten Ansatz bestanden haben, während die Tests mit dem zweiten nicht funktionieren. Ich bin völlig ahnungslos, warum das so ist und würde mich freuen, wenn irgendjemand etwas dazu aufklären könnte.

Bearbeiten:

Vergessen, die eigentlichen Tests hinzuzufügen (mit Ansatz 2):

Mit folgendem HTML-Tag:

%Vor%

Ich führe 4 getrennte Tests durch:

%Vor%

Der Fehler ist mit folgender Nachricht:

%Vor%

Wenn das HTML-Tag nicht vorhanden ist, schlagen alle 4 Tests fehl.

Bearbeiten 2:

Ich habe einen anderen Ansatz versucht, um zu überprüfen, ob der Kontrollfluss korrekt ist:

Ansatz 3:

%Vor%

Bei diesem Ansatz ist das Verhalten das gleiche wie bei Ansatz 2 - der erste Test schlägt nach 3 Pass fehl.

Die Ausgabe ist die folgende:

  

Wenn if: message: nil
  In außer, Nachricht lautet: "Profil aktualisiert"

Der Kontrollfluss sieht also gut aus, aber

%Vor%

schlägt fehl, obwohl es außerhalb des Matcher passiert. Das ist wirklich ein Mysterium.

Letzte Änderung:

Nur als Antwort auf die genehmigte Antwort - wenn ich den Code so umschalte:

%Vor%

Die Tests sehen so aus:

%Vor%

Ich denke also, dass die letzte Zeile, wenn sie nicht wahr ist, zu null ausgewertet wird, und das verursacht das ganze Durcheinander. Der erste Ansatz ist sowieso besser, aber ich bin froh, dass ich dieses Problem nicht im Kopf habe:)

    
STT 01.12.2012, 19:58
quelle

2 Antworten

6

Dies ist korrektes Verhalten für RSpec, auch wenn es unerwartet erscheint.

Betrachten Sie diesen Code:

%Vor%

Die ...unless -Anweisung gibt nil zurück, wenn die Bedingung falsch ist.

In Ihrem benutzerdefinierten Matcher gibt die ...unless -Anweisung null zurück, wenn Ihre Nachricht null ist.

Das ist die letzte Zeile in Ihrem Match-Block, also gibt Ihr Match-Block null zurück.

Dann erkennt RSpec, dass Ihr Match-Block den Wert nil zurückgibt, was RSpec als false ansieht, sodass RSpec meldet, dass Ihr benutzerdefinierter Matcher fehlgeschlagen ist.

    
joelparkerhenderson 01.12.2012, 20:48
quelle
3

Wow, das war ein nettes Puzzle! Der Schlüssel ist, dass die Methode match erwartungsgemäß ein boolesches Ergebnis liefert. In der ersten Option ist der implizite Rückgabewert das Ergebnis des if -Verzweigs, der true ist.

Warum ist es true ? Nun, should ist so definiert wie folgt:

%Vor%

Er delegiert an PositiveExpectationHandler , wessen handle_matcher Methode wie folgt aussieht:

%Vor%

Wir können sehen, dass, wenn der Matcher true (oder tatsächlich irgendeinen truthigen Wert) zurückgibt, dieser von der Funktion zurückgegeben wird und implizit der Rückgabewert von should wird. Ich bin mir nicht sicher, ob dieses Verhalten irgendwo dokumentiert ist.

In der zweiten Option wird jedoch der Wert des letzten Ausdrucks / der letzten Aussage gewonnen, und da die unless -Bedingung true ist, wird der Ausdruck zu nil :

ausgewertet %Vor%

Daher denkt RSpec, dass der Matcher versucht, Fehler zu melden, weil Sie versehentlich nil zurückgeben.

Um dies zu beheben, sollten Sie should im Matcher wahrscheinlich nicht verwenden. Sie können Capybaras HaveSelector matcher folgendermaßen aufrufen:

%Vor%

Übrigens führt die Angabe von text: nil eventuell zu hier wo es in der leeren Regexp resultieren wird, so dass die Überprüfung für nil sowieso nicht benötigt wird und Sie den Matcher wie folgt schreiben können:

%Vor%

Nicht sehr Rubyesque, ich gebe es zu, aber da gehst du.

    
Thomas 01.12.2012 22:05
quelle