Was ist der Unterschied zwischen let
und einem before
Block in RSpec?
Und wann jeweils zu verwenden?
Was ist ein guter Ansatz (lassen oder vorher) im folgenden Beispiel?
let(:user) { User.make !}
let(:account) {user.account.make!}
before(:each) do
@user = User.make!
@account = @user.account.make!
end
Ich habe diesen Stackoverflow-Beitrag studiert
Aber ist es gut, let für Assoziationssachen wie oben zu definieren?
ruby-on-rails
unit-testing
rspec
Kriysna
quelle
quelle
Antworten:
Die Leute scheinen einige der grundlegenden Arten, in denen sie sich unterscheiden, erklärt zu haben, haben sie jedoch ausgelassen
before(:all)
und erklären nicht genau, warum sie verwendet werden sollten.Ich bin der Meinung, dass Instanzvariablen in der überwiegenden Mehrheit der Spezifikationen keinen Platz haben, was teilweise auf die in dieser Antwort genannten Gründe zurückzuführen ist. Daher werde ich sie hier nicht als Option erwähnen.
Blöcke lassen
Code innerhalb eines
let
Blocks wird nur ausgeführt, wenn auf ihn verwiesen wird. Das verzögerte Laden bedeutet, dass die Reihenfolge dieser Blöcke irrelevant ist. Dies gibt Ihnen eine große Menge an Leistung, um die wiederholte Einrichtung durch Ihre Spezifikationen zu reduzieren.Ein (extrem kleines und erfundenes) Beispiel hierfür ist:
Sie können sehen, dass dies
has_moustache
jeweils unterschiedlich definiert ist, die Definition muss jedoch nicht wiederholt werdensubject
. Es ist wichtig zu beachten, dass der letztelet
im aktuellen Kontext definierte Block verwendet wird. Dies ist gut, um einen Standard festzulegen, der für die meisten Spezifikationen verwendet wird und bei Bedarf überschrieben werden kann.Zum Beispiel würde das Überprüfen des Rückgabewerts von,
calculate_awesome
wenn einperson
Modell mit dem Werttop_hat
true übergeben wurde, aber kein Schnurrbart wäre:Eine weitere Anmerkung zu let-Blöcken: Sie sollten nicht verwendet werden, wenn Sie nach etwas suchen, das in der Datenbank gespeichert wurde (dh
Library.find_awesome_people(search_criteria)
), da sie nicht in der Datenbank gespeichert werden, es sei denn, auf sie wurde bereits verwiesen.let!
oderbefore
Blöcke sollten hier verwendet werden.Auch nie jemals verwenden ,
before
um Trigger - Ausführung vonlet
Blöcken, das ist , waslet!
wird für!Lassen! Blöcke
let!
Blöcke werden in der Reihenfolge ausgeführt, in der sie definiert sind (ähnlich wie ein Vorher-Block). Der einzige wesentliche Unterschied zu früheren Blöcken besteht darin, dass Sie einen expliziten Verweis auf diese Variable erhalten, anstatt auf Instanzvariablen zurückgreifen zu müssen.Wenn wie bei
let
Blöcken mehrerelet!
Blöcke mit demselben Namen definiert sind, wird bei der Ausführung der neueste verwendet. Der Hauptunterschied besteht darin, dasslet!
Blöcke bei dieser Verwendung mehrmals ausgeführt werden, während derlet
Block nur das letzte Mal ausgeführt wird.vor (: jeweils) Blöcken
before(:each)
ist die Standardeinstellung vor dem Block und kann daher als jedes Mal angegeben werden,before {}
anstatt das vollständige anzugebenbefore(:each) {}
.Es ist meine persönliche Präferenz,
before
Blöcke in einigen Kernsituationen zu verwenden. Ich werde vor Blöcken verwenden, wenn:before { get :index }
). Obwohl Siesubject
dies in vielen Fällen verwenden können, fühlt es sich manchmal expliziter an, wenn Sie keine Referenz benötigen.Wenn Sie große
before
Blöcke für Ihre Spezifikationen schreiben , überprüfen Sie Ihre Fabriken und stellen Sie sicher, dass Sie die Merkmale und ihre Flexibilität vollständig verstehen.vor (: allen) Blöcken
Diese werden immer nur einmal vor den Spezifikationen im aktuellen Kontext (und ihren untergeordneten Elementen) ausgeführt. Diese können bei korrekter Schreibweise von großem Vorteil sein, da bestimmte Situationen die Ausführung und den Aufwand verringern können.
Ein Beispiel (das die Ausführungszeit kaum beeinflussen würde) ist das Verspotten einer ENV-Variablen für einen Test, was Sie immer nur einmal tun sollten.
Hoffentlich hilft das :)
quelle
before(:all)
Option in Minitest nicht vorhanden. Hier sind einige Problemumgehungen in den Kommentaren: github.com/seattlerb/minitest/issues/61its
ist nicht mehr in rspec-core. Ein moderner, idiomatischer Weg istit { is_expected.to be_awesome }
.Fast immer bevorzuge ich
let
. Der Beitrag, den Sie verlinken, gibt an, dass dieslet
auch schneller ist. Manchmal, wenn viele Befehle ausgeführt werden müssen, könnte ich sie verwenden,before(:each)
da die Syntax klarer ist, wenn viele Befehle beteiligt sind.In Ihrem Beispiel würde ich definitiv lieber verwenden
let
alsbefore(:each)
. Im Allgemeinen neige ich dazu, wenn nur eine variable Initialisierung durchgeführt wirdlet
.quelle
Ein großer Unterschied, der nicht erwähnt wurde, besteht darin, dass mit definierte Variablen
let
erst instanziiert werden, wenn Sie sie zum ersten Mal aufrufen. Während einbefore(:each)
Block alle Variablen instanziieren würde, könnenlet
Sie eine Reihe von Variablen definieren, die Sie möglicherweise für mehrere Tests verwenden. Diese werden jedoch nicht automatisch instanziiert. Ohne dies zu wissen, könnten Ihre Tests zurückkehren, um sich selbst zu beißen, wenn Sie erwarten, dass alle Daten im Voraus geladen werden. In einigen Fällen möchten Sie möglicherweise sogar eine Reihe vonlet
Variablen definieren und dann mit einembefore(:each)
Block jedelet
Instanz aufrufen , um sicherzustellen, dass die Daten zunächst verfügbar sind.quelle
let!
Methoden definieren, die vor jedem Beispiel aufgerufen werden. Siehe RSpec-Dokumente .Es sieht so aus, als würden Sie Machinist verwenden. Achtung, es können Probleme mit make auftreten! Innerhalb von let (der Non-Bang-Version), das außerhalb der globalen Fixture-Transaktion stattfindet (wenn Sie auch Transaktions-Fixtures verwenden), wodurch die Daten für Ihre anderen Tests beschädigt werden.
quelle