479 Stimmen

Wann sollte RSpec let() verwendet werden?

Ich neige dazu, vor Blöcken zu verwenden, um Instanzvariablen zu setzen. Diese Variablen verwende ich dann in meinen Beispielen. Vor kurzem stieß ich auf let() . Laut den RSpec-Dokumenten wird es verwendet, um

... um eine memoisierte Hilfsmethode zu definieren. Der Wert wird bei mehreren Aufrufen im selben Beispiel zwischengespeichert, aber nicht über Beispiele hinweg.

Wie unterscheidet sich dies von der Verwendung von Instanzvariablen in Before-Blöcken? Und auch wann sollte man let() gegen before() ?

632voto

Myron Marston Punkte 20741

Ich bevorzuge immer let auf eine Instanzvariable aus mehreren Gründen:

  • Instanzvariablen entstehen, wenn sie referenziert werden. Das bedeutet, dass, wenn Sie die Schreibweise der Instanzvariablen mit dem Finger eingeben, eine neue Variable erstellt und mit nil was zu subtilen Fehlern und falsch positiven Ergebnissen führen kann. Da let eine Methode erstellt, erhalten Sie eine NameError wenn Sie es falsch schreiben, was ich besser finde. Es macht es auch einfacher, Spezifikationen zu refaktorisieren.
  • A before(:each) Hook wird vor jedem Beispiel ausgeführt, auch wenn das Beispiel keine der im Hook definierten Instanzvariablen verwendet. Normalerweise ist das keine große Sache, aber wenn das Einrichten der Instanzvariablen viel Zeit in Anspruch nimmt, dann verschwenden Sie Zyklen. Für die Methode, die durch let wird der Initialisierungscode nur ausgeführt, wenn das Beispiel ihn aufruft.
  • Sie können von einer lokalen Variable in einem Beispiel direkt in ein let refaktorisieren, ohne die Referenzierungssyntax im Beispiel zu ändern. Wenn Sie auf eine Instanzvariable refaktorisieren, müssen Sie ändern wie Sie das Objekt im Beispiel referenzieren (z. B. durch Hinzufügen eines @ ).
  • Das ist zwar etwas subjektiv, aber wie Mike Lewis schon sagte, finde ich, dass die Spezifikation dadurch leichter zu lesen ist. Mir gefällt die Organisation der Definition all meiner abhängigen Objekte mit let und die Beibehaltung meiner it Block schön und kurz.

Ein entsprechender Link ist hier zu finden: http://www.betterspecs.org/#let

87voto

Mike Lewis Punkte 62061

Der Unterschied zwischen der Verwendung von Instanzvariablen und let() ist, dass let() es Faulheit bewertet . Dies bedeutet, dass let() wird erst ausgewertet, wenn die Methode, die sie definiert, zum ersten Mal ausgeführt wird.

Der Unterschied zwischen before y let ist das let() gibt Ihnen eine gute Möglichkeit, eine Gruppe von Variablen in einem "kaskadierenden" Stil zu definieren. Auf diese Weise wird die Spezifikation durch die Vereinfachung des Codes ein wenig besser aussehen.

20voto

Ho-Sheng Hsiao Punkte 1275

Ich habe alle Verwendungen von Instanzvariablen in meinen rspec-Tests vollständig durch die Verwendung von let() ersetzt. Ich habe ein kurzes Beispiel für einen Freund geschrieben, der damit einen kleinen Rspec-Kurs unterrichtet hat: http://ruby-lambda.blogspot.com/2011/02/agile-rspec-with-let.html

Wie einige der anderen Antworten hier sagt, ist let() lazy ausgewertet, so dass es nur die laden, die Laden erfordern. Es trocknet die Spezifikation aus und macht sie lesbarer. Ich habe in der Tat portiert die Rspec let() Code in meinen Controllern zu verwenden, im Stil der inherited_resource gem. http://ruby-lambda.blogspot.com/2010/06/stealing-let-from-rspec.html

Ein weiterer Vorteil ist, dass Sie in Kombination mit ActiveSupport::Concern und dem load-everything-in spec/support/-Verhalten Ihre eigene spec-Mini-DSL erstellen können, die speziell auf Ihre Anwendung zugeschnitten ist. Ich habe eine für das Testen gegen Rack und RESTful-Ressourcen geschrieben.

Die Strategie, die ich verwende, ist "Factory-everything" (über Machinist+Forgery/Faker). Es ist jedoch möglich, sie in Kombination mit before(:each)-Blöcken zu verwenden, um Fabriken für eine ganze Reihe von Beispielgruppen vorzuladen, wodurch die Spezifikationen schneller ausgeführt werden können: http://makandra.com/notes/770-taking-advantage-of-rspec-s-let-in-before-blocks

13voto

Pikachu Punkte 774

Es ist wichtig zu bedenken, dass lassen Sie faul ausgewertet wird und keine Methoden mit Seiteneffekten enthält, da man sonst nicht in der Lage wäre, von lassen Sie a vor(:jeder) leicht. Sie können verwenden lassen! anstelle von lassen Sie so dass sie vor jedem Szenario ausgewertet wird.

11voto

iftheshoefritz Punkte 4933

Andersdenkende Stimme hier: nach 5 Jahren rspec mag ich nicht let sehr viel.

1. Faule Auswertung macht den Testaufbau oft unübersichtlich

Es wird schwierig, über das Setup nachzudenken, wenn einige Dinge, die im Setup deklariert wurden, den Zustand nicht wirklich beeinflussen, während andere es tun.

Irgendwann ändert jemand aus Frustration einfach let a let! (dasselbe ohne faule Auswertung), um ihre Spezifikation zum Laufen zu bringen. Wenn das klappt, wird eine neue Gewohnheit geboren: Wenn eine neue Spezifikation zu einer älteren Suite hinzugefügt wird und nicht funktioniert, wird die erste der Autor versucht, Ponyfransen an zufälligen Stellen anzubringen. let Anrufe.

Schon bald sind alle Leistungsvorteile dahin.

2. Die spezielle Syntax ist für Nicht-rspec-Benutzer ungewohnt

Ich würde meinem Team lieber Ruby beibringen als die Tricks von rspec. Instanzvariablen oder Methodenaufrufe sind überall in diesem und anderen Projekten nützlich, let Syntax wird nur in rspec nützlich sein.

3. Die "Vorteile" erlauben es uns, gute Designänderungen einfach zu ignorieren

let() ist gut für teure Abhängigkeiten, die wir nicht immer wieder neu erstellen wollen. Es lässt sich auch gut mit subject die es Ihnen ermöglicht, wiederholte Aufrufe von Methoden mit mehreren Argumenten zu beenden

Teure Abhängigkeiten, die oft wiederholt werden, und Methoden mit großen Signaturen sind beides Punkte, an denen wir den Code verbessern könnten:

  • vielleicht kann ich eine neue Abstraktion einführen, die eine Abhängigkeit vom Rest meines Codes isoliert (was bedeuten würde, dass weniger Tests sie benötigen)
  • vielleicht macht der zu testende Code zu viel
  • vielleicht muss ich intelligentere Objekte anstelle einer langen Liste von Primitiven einfügen
  • Vielleicht habe ich gegen das Verbot verstoßen, etwas zu sagen, aber nicht zu fragen.
  • vielleicht kann der teure Code schneller gemacht werden (seltener - hier ist Vorsicht vor voreiliger Optimierung geboten)

In all diesen Fällen kann ich das Symptom schwieriger Tests mit einem beruhigenden Balsam aus rspec-Magie bekämpfen, oder ich kann versuchen, die Ursache zu beseitigen. Ich habe das Gefühl, dass ich in den letzten Jahren viel zu viel Zeit mit Ersterem verbracht habe, und jetzt möchte ich besseren Code.

Um die ursprüngliche Frage zu beantworten: Ich würde es vorziehen, es nicht zu tun, aber ich verwende trotzdem let . I meist es verwenden, um sich dem Stil des restlichen Teams anzupassen (es scheint, als ob die meisten Rails-Programmierer auf der Welt jetzt tief in ihrer rspec-Magie stecken, also ist das sehr oft der Fall). Manchmal verwende ich es, wenn ich einen Test zu einem Code hinzufüge, über den ich keine Kontrolle habe, oder keine Zeit für ein Refactoring zu einer besseren Abstraktion habe: d.h. wenn die einzige Option das Schmerzmittel ist.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X