it-swarm.com.de

RSpec: Was ist der Unterschied zwischen let und a before block?

Was ist der Unterschied zwischen let und einem before Block in RSpec?

Und wann soll man jeweils nutzen?

Was ist im folgenden Beispiel ein guter Ansatz (let oder before)?

let(:user) { User.make !}
let(:account) {user.account.make!}

before(:each) do
 @user = User.make!
 @account = @user.account.make!
end

Ich habe das studiert stackoverflow post

Aber ist es gut, let for association stuff wie oben zu definieren?

86
kriysna

Die Leute scheinen einige der grundlegenden Unterschiede erklärt zu haben, haben jedoch before(:all) ausgelassen und erklären nicht genau, warum sie verwendet werden sollten.

Ich bin der Meinung, dass Instanzvariablen in den meisten Spezifikationen keinen Platz haben, was zum Teil auf die in diese Antwort genannten Gründe zurückzuführen ist. Deshalb werde ich sie hier nicht als Option erwähnen.

lass Blöcke

Code innerhalb eines let -Blocks wird nur ausgeführt, wenn darauf verwiesen wird. Ein verzögertes Laden bedeutet, dass die Reihenfolge dieser Blöcke irrelevant ist. Dies gibt Ihnen eine große Menge an Energie, um wiederholte Einstellungen durch Ihre Spezifikationen zu reduzieren.

Ein (extrem kleines und erfundenes) Beispiel dafür ist:

let(:person)     { build(:person) }
subject(:result) { Library.calculate_awesome(person, has_moustache) }

context 'with a moustache' do
  let(:has_moustache) { true } 
  its(:awesome?)      { should be_true }
end

context 'without a moustache' do
  let(:has_moustache) { false } 
  its(:awesome?)      { should be_false }
end

Sie können sehen, dass has_moustache in jedem Fall anders definiert ist, aber Sie müssen die subject -Definition nicht wiederholen. Zu beachten ist, dass der letzte im aktuellen Kontext definierte let -Block verwendet wird. Dies ist nützlich, um einen Standard für die meisten Spezifikationen festzulegen, der bei Bedarf überschrieben werden kann.

Wenn Sie beispielsweise den Rückgabewert von calculate_awesome überprüfen, wenn Sie ein person -Modell mit top_hat auf true übergeben, aber kein Schnurrbart:

context 'without a moustache but with a top hat' do
  let(:has_moustache) { false } 
  let(:person)        { build(:person, top_hat: true) }
  its(:awesome?)      { should be_true }
end

Eine weitere Anmerkung zu let-Blöcken: Sie sollten nicht verwendet werden, wenn Sie nach etwas suchen, das in der Datenbank gespeichert wurde (z. B. Library.find_awesome_people(search_criteria)), da sie nur dann in der Datenbank gespeichert werden, wenn dies bereits geschehen ist verwiesen worden. let! oder before Blöcke sind hier zu verwenden.

Außerdem wird mit never ever before zum Auslösen der Ausführung von let Blöcke, dafür ist let! gemacht!

lass! Blöcke

let! Blöcke werden in der Reihenfolge ausgeführt, in der sie definiert sind (ähnlich wie ein vorheriger Block). Der Hauptunterschied zu vor Blöcken besteht darin, dass Sie einen expliziten Verweis auf diese Variable erhalten, anstatt auf Instanzvariablen zurückgreifen zu müssen.

Wie bei let Blöcken wird bei der Ausführung der letzte verwendet, wenn mehrere let! Blöcke mit demselben Namen definiert sind. Der Hauptunterschied besteht darin, dass let! Blöcke bei dieser Verwendung mehrfach ausgeführt werden, während der let Block nur das letzte Mal ausgeführt wird.

vor (: jedem) Block

before(:each) ist die Standardeinstellung vor dem Block und kann daher als before {} bezeichnet werden, anstatt jedes Mal die vollständige before(:each) {} anzugeben.

Es ist meine persönliche Präferenz, before Blöcke in einigen Kernsituationen zu verwenden. Ich werde vor Blöcken verwenden, wenn:

  • Ich benutze Mocking, Stubbing oder Doubles
  • Es gibt ein Setup in angemessener Größe (im Allgemeinen ist dies ein Zeichen dafür, dass Ihre Werksmerkmale nicht korrekt eingerichtet wurden).
  • Es gibt eine Reihe von Variablen, auf die ich nicht direkt verweisen muss, die aber für das Setup erforderlich sind
  • Ich schreibe funktionale Controller-Tests in Rails und möchte eine bestimmte Anforderung zum Testen ausführen (d. H. before { get :index }). Obwohl Sie in vielen Fällen subject dafür verwenden könnten, fühlt es sich manchmal expliziter an, wenn Sie keine Referenz benötigen.

Wenn Sie feststellen, dass Sie große before Blöcke für Ihre Spezifikationen schreiben, überprüfen Sie Ihre Fabriken und stellen Sie sicher, dass Sie die Eigenschaften und ihre Flexibilität vollständig verstehen.

vor (: allen) Blöcken

Diese werden immer nur einmal ausgeführt, vor den Angaben im aktuellen Kontext (und seinen untergeordneten Elementen). Diese können bei korrekter Schreibweise von großem Vorteil sein, da sie in bestimmten Situationen die Ausführung und den Aufwand verringern können.

Ein Beispiel (das sich kaum auf die Ausführungszeit auswirken würde) ist das Verspotten einer ENV-Variablen für einen Test, den Sie nur einmal ausführen müssen.

Ich hoffe, das hilft :)

134
Jay

Fast immer bevorzuge ich let. Der Beitrag, den Sie verknüpfen, gibt an, dass let auch schneller ist. Manchmal jedoch, wenn viele Befehle ausgeführt werden müssen, könnte ich before(:each) verwenden, da die Syntax bei vielen Befehlen klarer ist.

In Ihrem Beispiel würde ich definitiv die Verwendung von let anstelle von before(:each) bevorzugen. Im Allgemeinen bevorzuge ich die Verwendung von let, wenn nur eine Variableninitialisierung durchgeführt wird.

25
Spyros

Ein großer Unterschied, der nicht erwähnt wurde, ist, dass mit let definierte Variablen erst instanziiert werden, wenn Sie ihn das erste Mal aufrufen. Während ein before(:each) -Block alle Variablen instanziiert, können Sie mit let eine Reihe von Variablen definieren, die Sie möglicherweise über mehrere Tests hinweg verwenden, aber nicht automatisch instanziieren. Ohne dies zu wissen, könnten sich Ihre Tests selbst beißen, wenn Sie erwarten, dass alle Daten im Voraus geladen werden. In einigen Fällen möchten Sie möglicherweise sogar eine Reihe von let Variablen definieren und dann mit einem before(:each) Block jede let Instanz aufrufen, um sicherzustellen, dass die Daten verfügbar sind zunächst.

15
mikeweber

Sie arbeiten anscheinend mit Machinist. Achtung, bei make können Probleme auftreten! Innerhalb von let (der Nicht-Bang-Version), die außerhalb der globalen Fixture-Transaktion stattfindet (wenn Sie auch Transaktions-Fixtures verwenden), werden die Daten für Ihre anderen Tests beschädigt.

3
Tim Connor