Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. TDD

Fabrik-Mädchen 101

by
Read Time:18 minsLanguages:

German (Deutsch) translation by Valentina (you can also view the original English article)

Factory Girl imageFactory Girl imageFactory Girl image

Diese zweiteilige Miniserie wurde für Leute geschrieben, die in die Arbeit mit Fabrik-Mädchen einsteigen und auf den Punkt kommen möchten, ohne die Dokumentation für sich selbst zu durchforsten. Für Leute, die erst vor kurzem angefangen haben, mit Tests zu spielen, habe ich mein Bestes getan, um sie für Neulinge geeignet zu halten.

Nachdem ich irgendwann in den gleichen Schuhen gestanden habe, habe ich natürlich geglaubt, dass es nicht viel kostet, damit sich neue Leute beim Testen wohler fühlen. Wenn Sie sich etwas mehr Zeit nehmen, um den Kontext zu erklären und den Jargon zu entmystifizieren, können Sie die Frustrationsraten für Anfänger erheblich senken.

Inhalt

  • Intro und Kontext
  • Vorrichtungen
  • Aufbau
  • Fabriken definieren
  • Fabriken benutzen
  • Erbe
  • Mehrere Datensätze
  • Sequenzen

Intro und Kontext

Beginnen wir mit einem kleinen Stück Geschichte und sprechen wir über die feinen Leute bei Thoughtbot, die für dieses beliebte Ruby-Juwel verantwortlich sind. Bereits 2007/2008 hatte Joe Ferris, CTO bei Thoughtbot, es mit Fixtures zu tun und begann, seine eigene Lösung zu entwickeln. Das Durchsuchen verschiedener Dateien, um eine einzelne Methode zu testen, war ein häufiger Schmerzpunkt beim Umgang mit Vorrichtungen. Anders ausgedrückt und ohne Berücksichtigung aller Arten von Inflexibilitäten führt diese Übung auch dazu, dass Tests geschrieben werden, die nicht viel über den Kontext aussagen, der sofort getestet wird.

Da er diese derzeitige Praxis nicht verkaufte, prüfte er verschiedene Lösungen für Fabriken, aber keine von ihnen unterstützte alles, was er wollte. Also entwickelte er Factory Girl, das das Testen mit Testdaten lesbarer, trockener und expliziter machte, indem es Ihnen den Kontext für jeden Test gab. Ein paar Jahre später übernahm Josh Clayton, Entwicklungsleiter bei Thoughtbot in Boston, die Leitung des Projekts. Im Laufe der Zeit ist dieses Juwel stetig gewachsen und zu einem „Fixpunkt“ in der Ruby-Community geworden.

Lassen Sie uns mehr über die Hauptschmerzpunkte sprechen, die Factory Girl löst. Wenn Sie Ihre Testsuite erstellen, haben Sie es mit vielen zugehörigen Datensätzen und mit Informationen zu tun, die sich häufig ändern. Sie möchten in der Lage sein, Datensätze für Ihre Integrationstests zu erstellen, die nicht spröde, einfach zu verwalten und explizit sind. Ihre Datenfabriken sollten dynamisch sein und auf andere Fabriken verweisen können - etwas, das teilweise über YAML-Fixtures aus alten Zeiten hinausgeht.

Eine weitere Annehmlichkeit, die Sie haben möchten, ist die Möglichkeit, Attribute für Objekte im laufenden Betrieb zu überschreiben. Mit Fabrik-Mädchen können Sie all das mühelos erledigen - angesichts der Tatsache, dass es in Ruby geschrieben ist und hinter den Kulissen viel Metaprogrammier-Hexerei stattfindet - und Sie erhalten eine großartige domänenspezifische Sprache, die die Augen schont auch.

Das Aufbauen Ihrer Fixture-Daten mit diesem Juwel kann als einfach, effektiv und insgesamt bequemer beschrieben werden als das Fummeln mit Fixtures. Auf diese Weise können Sie mehr mit Konzepten als mit den tatsächlichen Spalten in der Datenbank umgehen. Aber genug davon, das Gespräch zu führen, lassen Sie uns unsere Hände ein bisschen schmutzig machen.

Vorrichtungen?

Personen, die Erfahrung mit dem Testen von Anwendungen haben und sich nicht mit dem Konzept von Vorrichtungen auskennen müssen, können direkt zum nächsten Abschnitt springen. Dieser ist für Neulinge gedacht, die nur ein Update zum Testen von Daten benötigen.

Fixtures sind Beispieldaten - das ist es wirklich! Für einen guten Teil Ihrer Testsuite möchten Sie in der Lage sein, Ihre Testdatenbank mit Daten zu füllen, die auf Ihre spezifischen Testfälle zugeschnitten sind. Viele Entwickler verwendeten YAML für eine Weile für diese Daten - was sie datenbankunabhängig machte. Im Nachhinein mag es das Beste gewesen sein, auf diese Weise unabhängig zu sein. Es war mehr oder weniger eine Datei pro Modell. Das allein könnte Ihnen eine Vorstellung von allen Arten von Kopfschmerzen geben, über die sich die Leute beschwert haben. Komplexität ist ein schnell wachsender Feind, mit dem YAML kaum effektiv umgehen kann. Unten sehen Sie, wie eine solche .yml-Datei mit Testdaten aussieht.

YAML-Datei: secret_service.yml

Es sieht aus wie ein Hash, nicht wahr? Es handelt sich um eine durch Doppelpunkte getrennte Liste von Schlüssel/Wert-Paaren, die durch ein Leerzeichen getrennt sind. Sie können andere Knoten ineinander referenzieren, wenn Sie Assoziationen aus Ihren Modellen simulieren möchten. Aber ich denke, es ist fair zu sagen, dass hier die Musik aufhört und viele sagen, dass ihr Schmerz beginnt. Für Datensätze, die etwas komplizierter sind, sind YAML-Fixtures schwer zu warten und schwer zu ändern, ohne andere Tests zu beeinflussen. Sie können sie natürlich zum Laufen bringen - schließlich haben Entwickler sie in der Vergangenheit häufig verwendet -, aber viele Leute waren sich einig, dass der Preis für die Verwaltung von Geräten etwas zu hoch war.

Um zu vermeiden, dass Ihre Testdaten bei unvermeidlichen Änderungen beschädigt werden, haben Entwickler gerne neuere Strategien eingeführt, die mehr Flexibilität und dynamisches Verhalten bieten. Hier kam Factory Girl ins Spiel und ließ die YAML-Tage hinter sich. Ein weiteres Problem ist die starke Abhängigkeit zwischen dem Test und der .yml-Fixture-Datei. Mystery-Gäste sind auch ein großer Schmerz bei solchen Armaturen. Mit Factory Girl können Sie dies vermeiden, indem Sie Objekte erstellen, die für die Inline-Tests relevant sind.

Sicher, YAML-Spiele sind schnell und ich habe gehört, dass Leute argumentieren, dass eine langsame Testsuite mit Factory Girl-Daten sie dazu gebracht hat, in das YAML-Land zurückzukehren. Wenn Sie Factory Girl so oft verwenden, dass es Ihre Tests wirklich verlangsamt, werden Sie möglicherweise Fabriken unnötig überbeanspruchen und Strategien ignorieren, die nicht in die Datenbank gelangen. Sie werden sehen, was ich meine, wenn wir zu den entsprechenden Abschnitten gelangen. Verwenden Sie natürlich alles, was Sie brauchen, aber seien Sie gewarnt, wenn Sie von YAML verbrannt werden.

Ich denke, es wäre fair hinzuzufügen, dass in den frühen Tagen von Rails und Ruby TDD YAML-Geräte der De-facto-Standard für die Einrichtung von Testdaten in Ihrer Anwendung waren. Sie spielten eine wichtige Rolle und trugen dazu bei, die Branche voranzubringen. Heutzutage haben sie allerdings einen ziemlich schlechten Ruf. Die Zeiten ändern sich, also gehen wir weiter zu Fabriken, die die Geräte ersetzen sollen.

Aufbau

Ich gehe davon aus, dass Sie Ruby und RSpec zum Testen bereits auf Ihrem System installiert haben. Wenn nicht, kommen Sie nach Rücksprache mit Google zurück und Sie sollten bereit sein. Es ist ganz einfach, würde ich sagen. Sie können den Edelstein manuell über Shell in Ihrem Terminal installieren:

oder fügen Sie es Ihrem Gemfile hinzu:

und führen Sie die bundle-install aus.

Jetzt müssen Sie nur noch Fabrik-Mädchen require, um Ihr Setup abzuschließen. Hier verwende ich RSpec. Fügen Sie daher oben in /spec/spec_helper.rb Folgendes hinzu:

Ruby on Rails

Sie sind natürlich abgesichert, wenn Sie Factory Girl with Rails verwenden möchten. Das factory_girl_rails-gem bietet eine praktische Rails-Integration für factory_girl.

Schell:

Gemfile:

und require Sie es natürlich in spec/spec_helper.rb:

Bequemes Syntax-Setup

Wenn Sie lieber etwas tippen wie (natürlich)

Ruby:

Anstatt von

Jedes Mal, wenn Sie eine Ihrer Fabriken verwenden, müssen Sie nur das FactoryGirl::Syntax::Methods-Modul in Ihre Testkonfigurationsdatei aufnehmen. Wenn Sie diesen Schritt vergessen, müssen Sie allen Factory Girl-Methoden dasselbe ausführliche Vorwort voranstellen. Dies funktioniert mit jeder Ruby-App, natürlich nicht nur mit Rails.

Suchen Sie für RSpec die Datei spec/spec_helper.rb und fügen Sie Folgendes hinzu:

Beachtung!

Achten Sie für die Neulinge unter Ihnen darauf, dass der RSpec.configure-Block bereits vorhanden ist - unter einigen Kommentaren begraben. Sie können dasselbe Setup auch in einer separaten Datei durchführen, z. B. spec /support/factory_girl.rb. In diesem Fall müssen Sie natürlich den gesamten Konfigurationsblock selbst hinzufügen.

Die gleiche Konfiguration funktioniert, wenn Sie andere Bibliotheken zum Testen verwenden:

  • Test::Unit
  • Cucumber
  • Spinach
  • MiniTest
  • MiniTest::Spec
  • Minitest-rails

Sie können Ihre Konfiguration ausgefallener gestalten, indem Sie beispielsweise DatabaseCleaner verwenden. Die Dokumentation impliziert jedoch, dass dieses Setup ausreicht, um loszulegen. Daher werde ich von hier aus fortfahren.

Fabriken definieren

Sie können Ihre Fabriken überall definieren, sie werden jedoch automatisch geladen, wenn sie an folgenden Orten platziert werden:

RSpec:

Test::Unit:

Wie Sie sehen können, haben Sie die Möglichkeit, sie in separate Dateien aufzuteilen, die der Logik entsprechen, oder Ihre Fabriken zu einer großen factories.rb-Datei zusammenzufassen. Die Komplexität Ihres Projekts ist die beste Richtlinie, um Fabriken logisch in ihre eigenen Dateien zu trennen.

Bare-Bones-Fabriken

Factory Girl bietet eine gut entwickelte Ruby-DSL-Syntax zum Definieren von Fabriken wie Benutzer, Post oder anderen Objekten - nicht nur Active Record-Objekten. "Einfache" Ruby-Klassen sind vollkommen in Ordnung. Sie beginnen mit dem Einrichten eines Definitionsblocks in Ihrer factories.rb-Datei.

Ruby:

Alle Fabriken sind in diesem Block definiert. Fabriken benötigen lediglich einen :symbol-Namen und eine Reihe von Attributen, um loszulegen. Dieser Name muss die snake_cased-Version des Modells sein, das Sie emulieren möchten - wie SecretServiceAgent im folgenden Beispiel. Die folgende Factory heißt secret_service_agent und verfügt über Attribute namens name, favor_gadget und skills.

Ruby:

Beachtung!

Wenn Sie eines von diesem Artikel wegnehmen, sollte es das Folgende sein: Definieren Sie nur die bestmögliche Factory, um standardmäßig gültig zu sein - beispielsweise im Sinne von Active Record-Validierungen.

Wenn Factory Girl save! auf Instanzen aufruft, werden Ihre Validierungen ausgeübt. Wenn eine von ihnen fehlschlägt, wird ActiveRecord::RecordInvalid ausgelöst. Wenn Sie nur das Nötigste definieren, erhalten Sie mehr Flexibilität, wenn sich Ihre Daten ändern, und verringern die Wahrscheinlichkeit, dass Tests und Duplikate abgebrochen werden, da die Kopplung auf den Kern reduziert wird. Seien Sie nicht faul, wenn Sie Ihre Fabriken zusammenstellen - es wird sich auszahlen!

Wenn Sie der Meinung sind, dass dies schwierig zu handhaben ist, werden Sie höchstwahrscheinlich erfreut sein zu hören, dass es praktische Lösungen gibt, um Objekte und ihre Attribute zu trennen. Vererbung und Eigenschaften werden zu großen Verbündeten, da sie praktische Strategien sind, um Ihre Bare-Bones-Fabriken zu ergänzen und sie gleichzeitig trocken zu halten. Erfahren Sie unten mehr über Vererbung, und mein zweiter Artikel wird sich ziemlich stark mit Merkmalen befassen.

Fabriken benutzen

Wenn Sie die FactoryGirl::Syntax::Methods in den Konfigurationsschritt aufgenommen haben, können Sie die Kurzschrift-Syntax verwenden, um Fabriken in Ihren Tests zu erstellen. Sie haben vier Optionen, die als Build-Strategien bezeichnet werden:

create 

Dieser gibt eine Instanz der Klasse zurück, die die Factory emuliert. Es wird empfohlen, create nur zu verwenden, wenn Sie wirklich auf die Datenbank zugreifen müssen. Diese Strategie verlangsamt Ihre Testsuite, wenn sie unnötig überbeansprucht wird. Verwenden Sie diese Option, wenn Sie Ihre Validierungen ausführen möchten, da sie save! im Hintergrund ausgeführt wird. Ich denke, diese Option ist vor allem dann angebracht, wenn Sie Integrationstests durchführen, bei denen Sie eine Datenbank für Ihre Testszenarien einbeziehen möchten.

build 

Es instanziiert und weist Attribute zu, aber Sie erhalten eine Instanz zurück, die nicht in der Datenbank gespeichert ist. build behält das Objekt nur im Speicher. Wenn Sie überprüfen möchten, ob ein Objekt bestimmte Attribute hat, erledigt dies die Aufgabe, da Sie für solche Dinge keinen Datenbankzugriff benötigen. Hinter den Kulissen wird save! nicht verwendet, was bedeutet, dass Ihre Validierungen nicht ausgeführt werden.

Kopf hoch!

Wenn Sie Assoziationen damit verwenden, können Sie auf eine kleine Gotcha stoßen. Es gibt eine kleine Ausnahme in Bezug darauf, dass das Objekt nicht über build gespeichert wird - es baut das Objekt, aber es erstellt die Assoziationen -, die ich im Abschnitt über Factory Girl-Assoziationen behandeln werde. Dafür gibt es eine Lösung, falls Sie nicht danach gesucht haben.

build_stubbed

Diese Option wurde erstellt, um Ihre Tests zu beschleunigen und um Testfälle durchzuführen, in denen kein Code in die Datenbank gelangen muss. Außerdem werden Attribute wie beim build instanziiert und zugewiesen, aber Objekte sehen nur so aus, als wären sie beibehalten worden. Das zurückgegebene Objekt enthält alle definierten Attribute aus Ihrer Fabrik - sowie eine gefälschte id und nil Zeitstempel. Ihre Assoziationen sind ebenfalls stubbed out - im Gegensatz zu build-Assoziationen, die create auf assoziierte Objekte verwenden. Da diese Strategie mit Stubs arbeitet und keine Abhängigkeit von der Datenbank hat, werden diese Tests so schnell wie möglich sein.

attributes_for

Diese Methode gibt nur einen Hash der in der jeweiligen Fabrik definierten Attribute zurück - natürlich ohne Zuordnungen, Zeitstempel und ID. Es ist praktisch, wenn Sie eine Instanz eines Objekts erstellen möchten, ohne manuell mit Attribut-Hashes herumzuspielen. Ich habe gesehen, dass es hauptsächlich in ähnlichen Controller-Spezifikationen verwendet wird:

Ruby:

Objektvergleich

Um diesen Abschnitt zu schließen, möchte ich Ihnen ein einfaches Beispiel geben, um die verschiedenen Objekte zu sehen, die von diesen vier Erstellungsstrategien zurückgegeben wurden. Im Folgenden können Sie die vier verschiedenen Objekte vergleichen, die Sie von attributes_for, create, build und build_stubbed erhalten:

Ich hoffe, dies war hilfreich, wenn Sie noch einige Unklarheiten darüber hatten, wie sie funktionieren und wann Sie welche Option verwenden sollten.

Erbe

Sie werden es lieben! Mit Vererbung können Sie Fabriken nur mit den notwendigen Attributen definieren, die jede Klasse zur Erstellung benötigt. Diese übergeordnete Fabrik kann so viele „untergeordnete“ Fabriken hervorbringen, wie Sie für geeignet halten, um alle Arten von Testszenarien mit unterschiedlichen Datensätzen abzudecken. Es ist sehr wichtig, dass Ihre Testdaten trocken bleiben, und die Vererbung erleichtert Ihnen dies erheblich.

Angenommen, Sie möchten einige Kernattribute in einer Fabrik definieren und haben innerhalb derselben Fabrik unterschiedliche Fabriken für dieselbe Klasse mit unterschiedlichen Attributen. Im folgenden Beispiel sehen Sie, wie Sie das Wiederholen von Attributen vermeiden können, indem Sie einfach Ihre Fabriken verschachteln. Emulieren wir eine Spy-Klasse, die sich an drei verschiedene Testszenarien anpassen muss.

factories.rb

some_spec.rb

Wie Sie sehen können, erben die Fabriken :bond und :quartermaster Attribute von ihrem übergeordneten :spy. Gleichzeitig können Sie Attribute bei Bedarf leicht überschreiben und über ihre Fabriknamen sehr aussagekräftig sein. Stellen Sie sich alle gespeicherten Codezeilen vor, da Sie nicht dieselbe Grundeinstellung wiederholen müssen, wenn Sie verschiedene Status oder verwandte Objekte testen möchten. Allein diese Funktion ist die Verwendung von Factory Girl wert und macht es schwierig, zu YAML-Fixtures zurückzukehren.

Wenn Sie das Verschachteln von Factory-Definitionen vermeiden möchten, können Sie Fabriken auch explizit mit ihrem übergeordneten Hash verknüpfen, indem Sie einen parent Hash angeben:

factories.rb

Es ist die gleiche Funktionalität und fast wie DRY.

Mehrere Datensätze

Hier ist eine kleine, aber dennoch willkommene Ergänzung zu Factory Girl, die den Umgang mit Listen zum Kinderspiel macht:

  • build_list
  • create_list

Von Zeit zu Zeit, in Situationen, in denen Sie mehrere Instanzen einer Fabrik ohne viel Flaum haben möchten, sind diese nützlich. Beide Methoden geben ein Array mit der angegebenen Anzahl von Factory-Elementen zurück. Ziemlich ordentlich, oder?

Ruby:

Es gibt subtile Unterschiede zwischen den beiden Optionen, aber ich bin sicher, dass Sie sie jetzt verstehen. Ich sollte auch erwähnen, dass Sie beide Methoden mit einem Hash von Attributen versehen können, wenn Sie aus irgendeinem Grund Factory-Attribute im laufenden Betrieb überschreiben möchten. Die Überschreibungen beeinträchtigen Ihre Testgeschwindigkeit, wenn Sie viele Testdaten mit Überschreibungen erstellen. Wahrscheinlich ist eine separate Factory mit diesen Attributen eine bessere Option zum Erstellen von Listen.

Sie benötigen häufig ein Paar Objekte, daher bietet Factory Girl zwei weitere Optionen:

  • build_pair
  • create_pair

Es ist die gleiche Idee wie oben, aber das zurückgegebene Array enthält jeweils nur zwei Datensätze.

Sequenzen

Wenn Sie dachten, Spione zu benennen könnte weniger statisch sein, haben Sie absolut Recht. In diesem letzten Abschnitt werden wir uns mit der Erstellung sequentieller eindeutiger Werte als Testdaten für Ihre Factory-Attribute befassen.

Wann könnte dies nützlich sein? Was ist zum Beispiel mit eindeutigen E-Mail-Adressen zum Testen der Authentifizierung oder eindeutigen Benutzernamen? Hier leuchten Sequenzen. Schauen wir uns einige verschiedene Möglichkeiten an, wie Sie sequence verwenden können:

"Globale" Sequenz

Da diese Sequenz für alle Ihre Fabriken "global" definiert ist - sie gehört nicht zu einer bestimmten Fabrik -, können Sie diesen Sequenzgenerator für alle Ihre Fabriken verwenden, wo immer Sie eine :spy_email benötigen. Alles was Sie brauchen ist generate und den Namen Ihrer Sequenz.

Attribute

Als kleine Variante, die sehr praktisch ist, zeige ich Ihnen, wie Sie Sequenzen direkt als Attribute Ihren Fabriken zuweisen können. Verwenden Sie dieselbe Bedingung wie oben, in der Ihre Sequenz "global" definiert ist. Bei einer Factory-Definition können Sie den generate-Methodenaufruf weglassen, und Factory Girl weist den zurückgegebenen Wert aus der Sequenz direkt dem gleichnamigen Attribut zu. Ordentlich!

"Lazy" Attribute

Sie können auch eine sequence für lazy Attribute verwenden. Ich werde dieses Thema in meinem zweiten Artikel behandeln, aber der Vollständigkeit halber wollte ich es auch hier erwähnen. Für den Fall, dass Sie einen eindeutigen Wert benötigen, der zum Zeitpunkt der Instanzerstellung zugewiesen wird - man nennt das "lazy", weil dieses Attribut mit der Wertzuweisung bis zur Instanziierung des Objekts wartet - brauchen Sie nur einen Block, um ebenfalls zu arbeiten.

Der Block für das Factory-Attribut wird ausgewertet, wenn das Objekt instanziiert wird. In unserem Fall erhalten Sie eine Zeichenfolge aus einer eindeutigen Missionsnummer und einem neuen DateTime-Objekt als Werte für jeden :spy, der bereitgestellt wird.

Inline-Sequenz

Diese Option ist am besten geeignet, wenn eine Folge eindeutiger Werte nur für ein Attribut für eine einzelne Fabrik benötigt wird. Es wäre nicht sinnvoll, es außerhalb dieser Fabrik zu definieren und möglicherweise anderswo danach zu suchen, wenn Sie es optimieren müssen. Im folgenden Beispiel möchten wir für jedes Spionageauto eindeutige IDs generieren.

Nun, vielleicht sollten wir dem vehicle_id_number-Attribut einen anderen Startwert als 1 geben? Nehmen wir an, wir möchten einige Prototypen berücksichtigen, bevor das Auto für die Produktion bereit war. Sie können ein zweites Argument als Startwert für Ihre Sequenz angeben. Lassen Sie uns diesmal mit 9 gehen.

Gedanken schließen

Wie Sie bereits gesehen haben, bietet Fabrik-Mädchen ein ausgewogenes Ruby-DSL, mit dem Objekte anstelle von Datenbankdatensätzen für Ihre Testdaten erstellt werden. Es hilft, Ihre Tests fokussiert, trocken und lesbar zu halten, wenn Sie mit Dummy-Daten arbeiten. Das ist eine ziemlich solide Leistung in meinem Buch.

Denken Sie daran, dass die Definitionen der Bare-Bones-Fabrik der Schlüssel für Ihre zukünftige Gesundheit sind. Je mehr Fabrikdaten Sie in Ihren globalen Testbereich eingeben, desto wahrscheinlicher treten Wartungsprobleme auf.

Für Ihre Unit-Tests ist Fabrik-Mädchen nicht erforderlich und verlangsamt nur Ihre Testsuite. Josh Clayton würde dies als erster bestätigen und empfehlen, Fabrik-Mädchen selektiv und so wenig wie möglich zu verwenden.

Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.