Ich bemühe mich, meinen Kopf um Rspec zu wickeln, um mich einem TDD / BDD-Entwicklungsmuster zu nähern. Ich bin jedoch weit davon entfernt, mit einigen der Grundlagen zu kämpfen:
Wie, wann genau sollte ich Mocks / Stubs verwenden und wann sollte ich nicht?
Nehmen wir zum Beispiel dieses Szenario: Ich habe ein Site
Modell, das has_many :blogs
und das Blog
Modell has_many :articles
. In meinem Site
-Modell habe ich einen Callback-Filter, der für jede neue Site einen Standardsatz von Blogs und Artikeln erstellt. Ich möchte diesen Code testen, also hier:
Wenn ich jetzt diesen Test mache, passiert alles. Es ist aber auch ziemlich langsam, da es eine neue Site, zwei neue Blogs und drei neue Artikel erstellt - für jeden einzelnen Test! Also frage ich mich, ist das ein guter Kandidat für die Verwendung von Stubs? Lass es uns versuchen:
%Vor%Jetzt sind alle Tests noch bestanden, und die Dinge sind auch ein bisschen schneller. Aber ich habe die Länge meiner Tests verdoppelt und die ganze Übung erscheint mir völlig sinnlos, weil ich meinen Code nicht mehr teste, sondern nur meine Tests teste.
Nun, entweder habe ich den Punkt von Mocks / Stubs völlig verpasst, oder ich nähere mich grundlegend falsch, aber ich hoffe, dass jemand in der Lage ist, entweder:
Aber ich habe die Dauer meiner Tests verdoppelt und die ganze Übung erscheint mir völlig sinnlos, weil ich meinen Code nicht mehr teste, sondern nur meine Tests teste.
Das ist der Schlüssel hier. Tests, die Ihren Code nicht testen, sind nicht sinnvoll. Wenn Sie den Code, den Ihre Tests testen sollen, negativ ändern können und die Tests nicht fehlschlagen, sind sie nicht wert.
Als Faustregel möchte ich nichts falsch machen / stupsen, es sei denn, ich muss es tun. Wenn ich beispielsweise einen Controller-Test schreibe und sicherstellen möchte, dass die entsprechende Aktion ausgeführt wird, wenn ein Datensatz nicht gespeichert werden kann, finde ich es einfacher, die save
-Methode des Objekts auf false zurückzusetzen, als sorgfältig zu basteln Parameter nur so, um sicherzustellen, dass ein Modell nicht speichern kann.
Ein weiteres Beispiel ist ein Helfer namens admin?
, der basierend auf der Frage, ob der aktuell angemeldete Benutzer ein Administrator ist oder nicht, nur wahr oder falsch zurückgibt. Ich wollte nicht fälschlicherweise einen Benutzer anmelden, also habe ich Folgendes getan:
Als Mittelweg möchten Sie vielleicht in Shoulda schauen. Auf diese Weise können Sie sicherstellen, dass Ihre Modelle eine Assoziation definiert haben, und darauf vertrauen, dass Rails gut genug getestet wurde, dass die Assoziation "einfach funktioniert", ohne dass Sie ein zugehöriges Modell erstellen und dann zählen müssen .
Ich habe ein Modell namens Member
, mit dem im Grunde alles in meiner App verwandt ist. Es hat 10 Assoziationen definiert. Ich könnte jede dieser Assoziationen testen, oder ich könnte das einfach tun:
Genau aus diesem Grund benutze ich Stubs / Mocks sehr selten (wirklich nur, wenn ich einen externen Webservice antrete). Die eingesparte Zeit ist die zusätzliche Komplexität nicht wert.
Es gibt bessere Möglichkeiten, die Testzeit zu verkürzen, und Nick Gauthier hält einen guten Vortrag über einige davon - siehe Video und die Folien .
Ich denke auch, dass es eine gute Option ist, eine In-Memory-SQLite-Datenbank für Ihre Testläufe auszuprobieren. Dies sollte Ihre Datenbankzeit um einiges reduzieren, indem Sie nicht auf die Festplatte für alles drücken müssen. Ich habe das selbst nicht versucht (ich verwende hauptsächlich MongoDB, das den gleichen Vorteil hat), also gehe vorsichtig vor. Hier ist ziemlich letzter Blogbeitrag dazu.
Ich bin mir nicht sicher, ob ich mich auf die anderen einlassen soll. Das wirkliche Problem (wie ich es sehe) hier ist, dass Sie mehrere Stücke von interessantem Verhalten mit denselben Tests testen (das Suchverhalten und die Erstellung). Aus Gründen, warum dies schlecht ist, lesen Sie diesen Vortrag: Ссылка . Ich nehme für den Rest dieser Antwort an, dass Sie testen möchten, dass die Erstellung das ist, was Sie testen möchten.
Isolationistische Tests erscheinen oft unhandlich, aber das liegt oft daran, dass sie Designlektionen haben, die Sie unterrichten. Im Folgenden sind einige grundlegende Dinge, die ich daraus sehen kann (obwohl, ohne den Produktionscode zu sehen, kann ich nicht viel Gutes tun).
Für Anfänger, um das Design abzufragen, macht es Sinn, die Site
Artikel zu einem Blog hinzuzufügen? Was ist mit einer Klassenmethode in Blog
, die etwas wie Blog.with_one_article
heißt? Das bedeutet dann, dass Sie nur testen müssen, dass diese Klassenmethode zweimal aufgerufen wurde (wenn [wie ich es jetzt verstehe]), haben Sie eine "primäre" und "sekundäre" Blog
für jede Site
, und das Verbände sind eingerichtet (ich habe noch keine gute Möglichkeit gefunden, dies in Schienen zu tun, ich teste es normalerweise nicht).
Darüber hinaus überschreiben Sie die Create-Methode von ActiveRecord, wenn Sie Site.create
aufrufen? Wenn dem so ist, würde ich vorschlagen, eine neue Klassenmethode auf der Site mit etwas anderem zu versehen ( Site.with_default_blogs
möglicherweise?). Dies ist nur eine allgemeine Angewohnheit von mir, das Überschreiben von Dingen verursacht in der Regel später Probleme in Projekten.
Tags und Links ruby unit-testing ruby-on-rails rspec mocking