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:)
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.
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:
Er delegiert an PositiveExpectationHandler
, wessen handle_matcher
Methode wie folgt aussieht:
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
:
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:
Ü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:
Nicht sehr Rubyesque, ich gebe es zu, aber da gehst du.
Tags und Links ruby capybara rspec railstutorial.org