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

Fabrikmädchen 201

by
Read Time:18 minsLanguages:

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

Final product imageFinal product imageFinal product image
What You'll Be Creating

Mein zweiter Artikel zu diesem beliebten und nützlichen Ruby-Juwel behandelt ein paar nuanciertere Themen, mit denen sich Anfänger nicht unbedingt gleich zu Beginn beschäftigen müssen. Auch hier habe ich mein Bestes getan, um es für Neulinge zugänglich zu machen und jedes bisschen Jargon zu erklären, über das Leute, die neu in Test-Driven Development (TDD) sind, stolpern könnten.

Themen

  • Abhängige Attribute
  • Transiente Attribute
  • Faule Attribute
  • Fabriken modifizieren
  • Rückrufe
  • Verbände
  • Aliase
  • Züge

Abhängige Attribute

Wenn Sie Attributwerte verwenden müssen, um andere Factory-Attribute im Handumdrehen zu erstellen, hat Factory Girl Sie abgedeckt. Sie müssen nur den Attributwert in einen Block einschließen und die benötigten Attribute interpolieren. Diese Blöcke haben Zugriff auf einen Evaluator – der ihnen überlassen wird – und der wiederum Zugriff auf andere Attribute hat, auch auf vorübergehende.

Transiente Attribute

Ich denke, es ist fair, sie als falsche Attribute zu bezeichnen. Mit diesen virtuellen Attributen können Sie beim Erstellen Ihrer Factory-Instanzen auch zusätzliche Optionen übergeben – natürlich über einen Hash. Die Instanz selbst ist davon nicht betroffen, da diese Attribute nicht für Ihr Factory-Objekt festgelegt werden. Auf der anderen Seite behandelt Factory Girl vergängliche Attribute wie echte.

Wenn Sie attributes_for verwenden, werden sie jedoch nicht angezeigt. Abhängige Attribute und Rückrufe können auf diese gefälschten Attribute in Ihrer Fabrik zugreifen. Insgesamt sind sie eine weitere Strategie, um Ihre Fabriken TROCKEN zu halten.

Das obige Beispiel fällt etwas trockener aus, da keine separaten Fabriken für Superschurken geschaffen werden mussten, die die Welt retten wollen bzw. mit Blofeld befreundet sind. Transiente Attribute geben Ihnen die Flexibilität, alle Arten von Anpassungen vorzunehmen und zu vermeiden, dass eine Vielzahl von noch so ähnlichen Fabriken erstellt wird.

Faule Attribute

„Normale“ Attribute in Factory Girl werden bei der Definition der Fabrik bewertet. Normalerweise stellen Sie statische Werte als Parameter für Methoden bereit, die denselben Namen wie Ihre Attribute haben. Wenn Sie die Auswertung bis zum letztmöglichen Moment verzögern möchten – wenn die Instanz instanziiert wird – müssen Sie den Attributen ihre Werte über einen Codeblock zuführen. Assoziationen und dynamisch erstellte Werte aus Objekten wie DateTime-Objekten werden Ihre häufigsten Kunden für diese faule Behandlung sein.

Fabriken modifizieren

Dies ist wahrscheinlich kein Anwendungsfall, auf den Sie jeden Tag stoßen werden, aber manchmal erben Sie Fabriken von anderen Entwicklern und möchten sie ändern – falls Sie beispielsweise ein TDD-Gem verwenden. Wenn Sie das Bedürfnis haben, diese Legacy-Fabriken zu optimieren, um sie besser an Ihre spezifischen Testszenarien anzupassen, können Sie sie ändern, ohne neue zu erstellen oder Vererbung zu verwenden.

Sie tun dies über FactoryGirl.modify, und es muss sich außerhalb des bestimmten FactoryGirl.define-Blocks befinden, den Sie ändern möchten. Was Sie nicht tun können, ist die sequence oder das Merkmal zu trait – Sie können jedoch die über trait definierten Attribute überschreiben. Rückrufe auf der „ursprünglichen“ Fabrik werden ebenfalls nicht überschrieben. Der Callback in Ihrem Factory.modify-Block wird einfach als nächster in der Zeile ausgeführt.

Im obigen Beispiel mussten unsere Spione etwas „ausgereifter“ sein und einen besseren Mechanismus verwenden, um die Bereitstellung zu handhaben. Ich habe Beispiele gesehen, in denen Gem-Autoren anders mit der Zeit umgehen mussten und wo es praktisch war, Factory-Objekte zu modifizieren, indem man einfach Dinge überschreibt, die man optimieren muss.

Rückrufe

Callbacks ermöglichen es Ihnen, Code zu verschiedenen Zeitpunkten im Lebenszyklus eines Objekts einzufügen – wie save, after_save, before_validation und so weiter. Rails bietet zum Beispiel eine ganze Reihe von ihnen und macht es Anfängern ziemlich einfach, diese Macht zu missbrauchen.

Denken Sie daran, dass Callbacks, die sich nicht auf die Persistenz von Objekten beziehen, ein bekanntes Anti-Muster sind, und es ist ein guter Rat, diese Grenze nicht zu überschreiten. Es mag beispielsweise bequem erscheinen, einen Rückruf zu verwenden, nachdem etwas wie ein Benutzer instanziiert wurde, um E-Mails zu senden oder eine Bestellung zu verarbeiten, aber diese Art von Dingen führt zu Fehlern und schafft Verbindungen, die unnötig schwer zu refaktorieren sind. Vielleicht war das einer der Gründe, warum Factory Girl dir „nur“ fünf Callback-Optionen zum Spielen anbietet:

  • before(:create) führt einen Codeblock aus, bevor Ihre Factory-Instanz gespeichert wird. Wird aktiviert, wenn Sie create(:some_object) verwenden.
  • after(:create) führt einen Codeblock aus, nachdem Ihre Factory-Instanz gespeichert wurde. Wird aktiviert, wenn Sie create(:some_object) verwenden.
  • after(:build) führt einen Codeblock aus, nachdem Ihr Factory-Objekt im Speicher gebaut wurde. Wird aktiviert, wenn Sie sowohl build(:some_object) als auch create(:some_object) verwenden.
  • after(:stub) führt einen Codeblock aus, nachdem Ihre Factory ein Stub-Objekt erstellt hat. Wird aktiviert, wenn Sie build_stubbed(:some_object) verwenden.
  • custom(:your_custom_callback) führt einen benutzerdefinierten Callback aus, ohne dass before oder after vorangestellt werden muss.

Beachtung!

Beachten Sie, dass Sie für alle Callback-Optionen innerhalb der Callback-Blöcke über einen Blockparameter auf eine Instanz der Factory zugreifen können. Dies wird sich ab und zu als nützlich erweisen, insbesondere bei Assoziationen.

Unten hat ein Ninja einen Haufen fieser Wurfsterne(Shuriken) zur Verfügung. Da Sie im Callback ein ninja-Objekt haben, können Sie den Wurfstern ganz einfach dem Ninja zuordnen. Werfen Sie einen Blick auf den Abschnitt über Assoziationen, wenn Sie bei diesem Beispiel ein paar Fragezeichen haben.

Außerdem haben Sie über das Evaluator-Objekt auch Zugriff auf transiente Attribute. Das gibt Ihnen die Möglichkeit, zusätzliche Informationen einzugeben, wenn Sie Factory-Objekte „erstellen“ und diese im Handumdrehen anpassen müssen. Das gibt Ihnen die nötige Flexibilität, um mit Assoziationen zu spielen und aussagekräftige Testdaten zu schreiben.

Wenn Sie feststellen, dass in Ihrer Fabrik mehrere Rückrufe erforderlich sind, steht Ihnen Factory Girl nicht im Weg – nicht einmal mehrere Arten. Die Reihenfolge der Ausführung ist natürlich von oben nach unten.

Der Teufel steckt natürlich im Detail. Wenn Sie create(:some_object) verwenden, werden sowohl after(:build) als auch after(:create) Callbacks ausgeführt.

Mehrere Build-Strategien können gebündelt werden, um auch denselben Callback auszuführen.

Zu guter Letzt können Sie sogar so etwas wie „globale“ Callbacks einrichten, die Callbacks für alle Factorys außer Kraft setzen – zumindest in dieser bestimmten Datei, wenn Sie sie in mehrere Factory-Dateien aufgeteilt haben.

factories/gun.rb

Beachtung!

Wenn Sie die Vererbung verwenden, um untergeordnete Factorys zu erstellen, werden auch die Callbacks der übergeordneten Factory vererbt.

Die letzte Meile

Lassen Sie uns in den folgenden Abschnitten alles über Assoziationen und Eigenschaften zusammenfassen – ja, ich habe mich auch eingeschlichen, weil es der beste Ort war, ohne überall herumzuspringen. Wenn Sie aufgepasst haben und sich an Dinge aus dem ersten Artikel erinnern, sollte jetzt alles ganz ordentlich zusammenpassen.

Verbände

Assoziationen sind für jede etwas komplexe Web-App mit Selbstachtung unerlässlich. Ein Beitrag, der einem Benutzer gehört, eine Auflistung mit vielen Bewertungen und so weiter sind das Brot und Butter, das Entwickler an jedem Tag der Woche zum Frühstück haben. Aus dieser Perspektive wird klar, dass Fabriken für komplexere Szenarien kugelsicher und einfach zu handhaben sein müssen – zumindest, um Ihr TDD-Mojo nicht durcheinander zu bringen.

Modellassoziationen über Factory Girl zu emulieren ist relativ einfach, würde ich sagen. Das an sich ist in meinen Augen schon erstaunlich. Ein hohes Maß an Einfachheit und Bequemlichkeit für die Erstellung komplexer Datensätze macht die Praxis von TDD zu einem Kinderspiel und so viel effektiver.

Das neue Q hat Hacker-Kenntnisse und muss einen anständigen Computer besitzen, oder? In diesem Fall haben Sie eine Computer-Klasse und ihre Instanzen gehören zu Instanzen der Quartermaster-Klasse. Einfach richtig?

Wie wäre es mit etwas mehr Engagement? Nehmen wir an, unsere Spione verwenden eine gun mit vielen cartridges (Kugeln).

Rückrufe sind bei Assoziationen ziemlich praktisch, oder? Jetzt können Sie eine Waffe mit oder ohne Munition bauen. Über die hash gun: gun haben Sie der cartridge-Fabrik die nötigen Informationen geliefert, um die Assoziation über den foreign_key zu erstellen.

Wenn Sie eine andere Magazingröße benötigen, können Sie diese über Ihr transientes Attribut übergeben.

Wie sieht es also mit den verschiedenen Build-Strategien aus? War da nicht was faul? Beachten Sie Folgendes: Wenn Sie für verknüpfte Objekte create verwenden, werden beide gespeichert. create(:quartermaster) erstellt und speichert sowohl Q als auch sein ThinkPad.

Ich würde also besser build verwenden, wenn ich vermeiden möchte, die Datenbank zu treffen, oder? Gute Idee, aber build würde in unserem Beispiel nur für quartermaster gelten – der zugehörige computer würde trotzdem gespeichert. Etwas knifflig, ich weiß. Wenn Sie das Speichern des verknüpften Objekts vermeiden müssen, können Sie Folgendes tun: Sie geben die Build-Strategie an, die Sie für Ihre Zuordnung benötigen.

Sie benennen das zugehörige Factory-Objekt und übergeben einen Hash mit Ihrer Build-Strategie. Damit dies funktioniert, müssen Sie den expliziten Assoziationsaufruf verwenden. Das folgende Beispiel funktioniert nicht.

Jetzt verwenden beide Objekte build und nichts wird in der Datenbank gespeichert. Wir können diese Annahme überprüfen, indem wir new_record? verwenden, das true zurückgibt, wenn die Instanz nicht beibehalten wurde.

Wenn wir schon dabei sind, können Sie über den expliziten Assoziationsaufruf auch auf verschiedene Fabriknamen verweisen und Attribute im Handumdrehen ändern.

Schließen wir dieses Kapitel mit einem polymorphen Beispiel.

Fühlen Sie sich nicht schlecht, wenn dieser etwas mehr Zeit zum Einsinken braucht. Ich empfehle, sich über polymorphe Assoziationen zu informieren, wenn Sie sich nicht sicher sind, was hier vor sich geht.

Aliase

Aliase für Ihre Factorys ermöglichen es Ihnen, den Kontext, in dem Sie Ihre Factory-Objekte verwenden, ausdrucksvoller zu gestalten. Sie müssen nur einen Hash mit alternativen Namen bereitstellen, die die Beziehung zwischen zugeordneten Objekten besser beschreiben.

Nehmen wir an, Sie haben eine :agent-Fabrik und eine :law_enforcement_vehicle-Fabrik. Wäre es nicht schön, den Agenten im Zusammenhang mit diesen Autos als :owner zu bezeichnen? Im folgenden Beispiel habe ich es einem Beispiel ohne Alias gegenübergestellt.

Beachtung!

Vergessen Sie nicht, einen Doppelpunkt vor der Alias-Factory (:owner) hinzuzufügen, wenn Sie sie für Assoziationen in Ihren Factorys verwenden. Die Dokumentation und viele Blogbeiträge verwenden sie in diesen Fällen ohne Doppelpunkte. Alles, was Sie erhalten, ist wahrscheinlich ein NoMethodError, da Ihnen jetzt eine Setter-Methode für diesen Alias fehlt. (Ich sollte besser eine Pull-Anfrage öffnen.) Das erste Mal, als ich darauf stieß, war ich verblüfft und es dauerte ein bisschen, bis ich daran vorbeikam. Denken Sie daran, Dokumentationen und Blogbeiträgen manchmal selektiv zu misstrauen. Ihr natürlich auch.

Ich denke, Sie werden mir zustimmen, dass die Verwendung von Aliasen nicht nur besser liest, sondern Ihnen oder der Person, die nach Ihnen kommt, auch etwas mehr Kontext zu den fraglichen Objekten gibt. Ja, Sie müssen plural :aliases auch verwenden, wenn Sie nur einen einzigen Alias haben.

Du könntest das auch etwas anders schreiben – viel ausführlicher.

Naja, nicht so ordentlich, oder?

Natürlich können Sie diese Aliase auch verwenden, um sofort Factory-Objekte zu „bauen“.

Im Kontext von Kommentaren könnte ein :user als :commenter bezeichnet werden, im Fall eines :crime könnte ein :user als :suspect bezeichnet werden und so weiter. Es ist wirklich kein Hexenwerk – eher praktischer syntaktischer Zucker, der Ihre Versuchung zur Vervielfältigung verringert.

Züge

Das ist eines meiner Lieblingsdinge an Factory Girl. Kurz gesagt, Eigenschaften sind Lego-ähnliche Blöcke, um Ihre Fabriken zu bauen und das Verhalten zu mischen. Sie sind durch Kommas getrennte Listen von Symboleigenschaften/Attributen, die Sie einer bestimmten Fabrik hinzufügen möchten, und sie sind auch in den Dateien Ihrer Fabriken definiert.

Meiner Meinung nach ist trait die leistungsstärkste und bequemste Funktion, um Ihre Werksdaten trocken zu halten und gleichzeitig ausdrucksstark zu sein. Es ermöglicht Ihnen, Gruppen von Attributen zu bündeln, ihnen separate Namen zu geben und sie nach Belieben wiederzuverwenden. Erinnern Sie sich, als ich Sie dazu drängte, nackte Fabrikobjekte zu definieren? Eigenschaften werden Ihnen dabei helfen, genau das zu erreichen, ohne auf Komfort zu verzichten.

Wie Sie sehen, können Sie einige Attribute, die auf mehrere Objekte verteilt sind, jetzt an einer zentralen Stelle ändern. Keine Schrotflinten-Operation notwendig. Die Verwaltung des Zustands über Merkmale könnte nicht bequemer sein.

Mit diesem Setup können Sie ziemlich ausgeklügelte Spionageautos bauen, indem Sie die verschiedenen Attributpakete nach Belieben mischen – ohne etwas zu duplizieren, indem Sie alle möglichen neuen Fabriken erstellen, die all die verschiedenen Optionen berücksichtigen, die Sie benötigen.

Sie können Traits mit create, build, build_stubbed und attribute_for verwenden. Wenn Q schlau wird, können Sie auch einzelne Attribute gleichzeitig überschreiben, indem Sie einen Hash übergeben.

Für Merkmalskombinationen, die in einer bestimmten Fabrik sehr häufig vorkommen, können Sie auch untergeordnete Fabriken mit Namen erstellen, die die verschiedenen Datensatzkombinationen am besten repräsentieren. Auf diese Weise bündeln Sie ihre Eigenschaften nur einmal und nicht immer, wenn Sie Testdaten erstellen.

Auf diese Weise können Sie diese Objekte prägnanter erstellen und sie sind auch besser lesbar.

Anstatt von:

Liest sich viel besser, oder? Vor allem, wenn keine Variablennamen beteiligt sind.

Sie können sogar Eigenschaften als Attribute für andere Eigenschaften und Fabriken wiederverwenden. Wenn Sie dieselben Attribute für mehrere Merkmale definieren, hat natürlich das zuletzt definierte Vorrang.

Achten Sie auf das Merkmal mobile_surveillance, das die cloaked getarnt und night_vision – im Grunde als Attribut. Auch die ultimate_spy_car-Factory, die ich diesmal zum Spaß aus der spy_car-Factory-Definition herausgenommen habe, verwendet alle Eigenschaften wieder und ein zusätzliches Attribut, das sie auch fliegen lässt. Reine Filmmagie – oder vielleicht sollte ich Factory Girl-Magie sagen.

create_list und build_list können auch Eigenschaften verwenden. Der zweite Parameter muss die Anzahl der gewünschten Factory-Instanzen sein.

Wäre es nicht cool, Assoziationen mit Merkmalen zu verwenden? Natürlich können Sie Callbacks und Assoziationen ordentlich in Merkmale packen. Äh!

Wie man sie benutzt, sollte jetzt langweilig sein.

Abschließende Gedanken

Letzte Worte der Weisheit: Veränderung ist Ihr ständiger Begleiter – Attribute oder Datentypen müssen ständig geändert werden. Designentscheidungen wie diese entwickeln sich weiter. Merkmale werden damit den Schmerz lindern und Ihnen helfen, Ihre Datensätze zu verwalten.

Stellen Sie sich vor, Sie hätten einen Options-Hash für die Instanziierung verwendet und diese Anforderung hätte sich komplett geändert. Wie viele potenzielle Stellen in Ihren Tests könnten brechen und müssen jetzt beachtet werden? Das trait ist ein sehr effektives Werkzeug, um Duplikate in Ihrer Testsuite zu vermeiden. Aber seien Sie bei all dieser Bequemlichkeit nicht faul und vergessen Sie Ihre Unit-Tests in den Spalten, die durch Ihre Eigenschaften repräsentiert werden! Auf diese Weise geben Sie ihnen die gleiche Sorgfalt wie den Barebone-Attributen, die für gültige Objekte erforderlich sind.

In Factory Girl gibt es noch ein bisschen mehr zu entdecken, und ich bin mir sicher, dass Sie jetzt mehr als gut gerüstet sind, um die Teile zusammenzusetzen, wenn Sie sie brauchen. Viel Spaß beim Spielen mit diesem Schmuckstück. Ich hoffe, Ihre TDD-Gewohnheiten werden davon profitieren.

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.