Duplizierter Code ist im Unit-Test-Code genauso ein Geruch wie in anderem Code. Wenn Sie Code in Tests dupliziert haben, ist es schwieriger, den Implementierungscode umzugestalten, da Sie überproportional viele Tests aktualisieren müssen. Tests sollten Ihnen dabei helfen, sicher umzugestalten, anstatt eine große Belastung zu sein, die Ihre Arbeit an dem zu testenden Code behindert.
Wenn sich die Duplizierung im Fixture-Setup befindet, sollten Sie die setUp
Methode stärker nutzen oder mehr (oder flexiblere) Erstellungsmethoden bereitstellen .
Wenn sich die Duplizierung im Code befindet, der das SUT manipuliert, fragen Sie sich, warum mehrere sogenannte "Unit" -Tests genau dieselbe Funktionalität ausüben.
Wenn die Duplizierung in den Zusicherungen enthalten ist, benötigen Sie möglicherweise einige benutzerdefinierte Zusicherungen . Zum Beispiel, wenn mehrere Tests eine Reihe von Aussagen haben wie:
assertEqual('Joe', person.getFirstName())
assertEqual('Bloggs', person.getLastName())
assertEqual(23, person.getAge())
Dann brauchen Sie vielleicht eine einzige assertPersonEqual
Methode, damit Sie schreiben können assertPersonEqual(Person('Joe', 'Bloggs', 23), person)
. (Oder Sie müssen den Gleichheitsoperator einfach überladen Person
.)
Wie Sie bereits erwähnt haben, ist es wichtig, dass der Testcode lesbar ist. Insbesondere ist es wichtig, dass die Absicht eines Tests klar ist. Ich finde, wenn viele Tests größtenteils gleich aussehen (z. B. drei Viertel der Linien gleich oder praktisch gleich), ist es schwierig, die signifikanten Unterschiede zu erkennen, ohne sie sorgfältig zu lesen und zu vergleichen. Daher finde ich, dass Refactoring zum Entfernen von Duplikaten die Lesbarkeit verbessert, da jede Zeile jeder Testmethode direkt für den Zweck des Tests relevant ist. Das ist für den Leser viel hilfreicher als eine zufällige Kombination von Zeilen, die direkt relevant sind, und Zeilen, die nur als Boilerplate dienen.
Allerdings üben Tests manchmal komplexe Situationen aus, die ähnlich, aber immer noch erheblich unterschiedlich sind, und es ist schwierig, einen guten Weg zu finden, um die Doppelarbeit zu reduzieren. Verwenden Sie den gesunden Menschenverstand: Wenn Sie der Meinung sind, dass die Tests lesbar sind und ihre Absicht klarstellen, und Sie möglicherweise mehr als eine theoretisch minimale Anzahl von Tests aktualisieren müssen, wenn Sie den von den Tests aufgerufenen Code umgestalten, akzeptieren Sie die Unvollkommenheit und verschieben Sie sie auf etwas produktiveres. Sie können jederzeit zurückkommen und die Tests später umgestalten, wenn Inspiration aufkommt!
Die Lesbarkeit ist für Tests wichtiger. Wenn ein Test fehlschlägt, soll das Problem offensichtlich sein. Der Entwickler sollte nicht viel stark faktorisierten Testcode durchgehen müssen, um genau zu bestimmen, was fehlgeschlagen ist. Sie möchten nicht, dass Ihr Testcode so komplex wird, dass Sie Unit-Test-Tests schreiben müssen.
Das Eliminieren von Duplikaten ist jedoch normalerweise eine gute Sache, solange nichts verdeckt wird. Das Eliminieren von Duplikaten in Ihren Tests kann zu einer besseren API führen. Stellen Sie nur sicher, dass Sie nicht über den Punkt hinausgehen, an dem die Renditen sinken.
quelle
Implementierungscode und Tests sind unterschiedliche Tiere und Factoring-Regeln gelten für sie unterschiedlich.
Doppelter Code oder doppelte Struktur riechen immer im Implementierungscode. Wenn Sie anfangen, Boilerplate in der Implementierung zu haben, müssen Sie Ihre Abstraktionen überarbeiten.
Auf der anderen Seite muss der Testcode einen Duplizierungsgrad beibehalten. Durch die Vervielfältigung des Testcodes werden zwei Ziele erreicht:
Ich neige dazu, triviale Duplikate im Testcode zu ignorieren, solange jede Testmethode kürzer als etwa 20 Zeilen bleibt. Ich mag es, wenn der Setup-Run-Verify-Rhythmus in Testmethoden sichtbar ist.
Wenn sich im "Verifizieren" -Teil von Tests Duplikate bilden, ist es häufig vorteilhaft, benutzerdefinierte Assertionsmethoden zu definieren. Natürlich müssen diese Methoden immer noch eine klar identifizierte Beziehung testen, die im Methodennamen deutlich wird:
assertPegFitsInHole
-> gut,assertPegIsGood
-> schlecht.Wenn Testmethoden langwierig und sich wiederholend werden, finde ich es manchmal nützlich, Testvorlagen zum Ausfüllen der Lücken zu definieren, die einige Parameter enthalten. Anschließend werden die eigentlichen Testmethoden auf einen Aufruf der Template-Methode mit den entsprechenden Parametern reduziert.
Für viele Dinge beim Programmieren und Testen gibt es keine eindeutige Antwort. Sie müssen einen Geschmack entwickeln, und der beste Weg, dies zu tun, besteht darin, Fehler zu machen.
quelle
Sie können die Wiederholung mithilfe verschiedener Testmethoden reduzieren .
Ich bin toleranter gegenüber Wiederholungen im Testcode als im Produktionscode, aber ich war manchmal frustriert darüber. Wenn Sie das Design einer Klasse ändern und 10 verschiedene Testmethoden anpassen müssen, die alle dieselben Einrichtungsschritte ausführen, ist dies frustrierend.
quelle
Genau. Der Kompromiss besteht, ist aber an verschiedenen Orten unterschiedlich.
Es ist wahrscheinlicher, dass ich doppelten Code zum Einrichten des Status umgestalte. Es ist jedoch weniger wahrscheinlich, dass der Teil des Tests, der den Code tatsächlich ausführt, überarbeitet wird. Das heißt, wenn das Ausüben des Codes immer mehrere Codezeilen erfordert, könnte ich denken, dass dies ein Geruch ist, und den tatsächlich getesteten Code umgestalten. Dies verbessert die Lesbarkeit und Wartbarkeit sowohl des Codes als auch der Tests.
quelle
Jay Felder prägte den Satz , dass „DSLs DAMP werden sollte, nicht trocken“, wo DAMP Mittel beschreibende und bedeutungsvollen Phrasen . Ich denke, dasselbe gilt auch für Tests. Offensichtlich ist zu viel Vervielfältigung schlecht. Das Entfernen von Duplikaten um jeden Preis ist jedoch noch schlimmer. Tests sollten als aufschlussreiche Spezifikationen dienen. Wenn Sie beispielsweise dasselbe Feature aus verschiedenen Blickwinkeln angeben, ist ein gewisses Maß an Duplizierung zu erwarten.
quelle
Ich LIEBE rspec aus diesem Grund:
Es gibt zwei Dinge zu helfen -
gemeinsame Beispielgruppen zum Testen des allgemeinen Verhaltens.
Sie können eine Reihe von Tests definieren und diese dann in Ihre realen Tests einbeziehen.
verschachtelte Kontexte.
Sie können im Wesentlichen eine "Setup" - und "Teardown" -Methode für eine bestimmte Teilmenge Ihrer Tests verwenden, nicht nur für jeden in der Klasse.
Je früher .NET / Java / andere Test-Frameworks diese Methoden anwenden, desto besser (oder Sie können IronRuby oder JRuby verwenden, um Ihre Tests zu schreiben, was meiner Meinung nach die bessere Option ist).
quelle
Ich bin der Meinung, dass Testcode ein ähnliches technisches Niveau erfordert, das normalerweise auf Produktionscode angewendet wird. Es kann durchaus Argumente für die Lesbarkeit geben, und ich würde zustimmen, dass dies wichtig ist.
Nach meiner Erfahrung sind gut faktorisierte Tests jedoch leichter zu lesen und zu verstehen. Wenn es 5 Tests gibt, die bis auf eine geänderte Variable und die Behauptung am Ende gleich aussehen, kann es sehr schwierig sein, das einzelne unterschiedliche Element zu finden. Wenn berücksichtigt wird, dass nur die sich ändernde Variable und die Behauptung sichtbar sind, ist es ebenfalls einfach, sofort herauszufinden, was der Test tut.
Es kann schwierig sein, beim Testen die richtige Abstraktionsebene zu finden, und ich halte es für sinnvoll, dies zu tun.
quelle
Ich glaube nicht, dass es eine Beziehung zwischen mehr dupliziertem und lesbarem Code gibt. Ich denke, Ihr Testcode sollte so gut sein wie Ihr anderer Code. Nicht wiederholter Code ist besser lesbar als duplizierter Code, wenn er gut gemacht wird.
quelle
Im Idealfall sollten sich Unit-Tests nach dem Schreiben nicht wesentlich ändern, sodass ich mich der Lesbarkeit zuwenden würde.
Wenn Unit-Tests so diskret wie möglich sind, können Sie die Tests auch auf die spezifischen Funktionen konzentrieren, auf die sie abzielen.
Trotzdem versuche ich, bestimmte Codeteile, die ich immer wieder verwende, wiederzuverwenden, z. B. Setup-Code, der für eine Reihe von Tests genau gleich ist.
quelle
"Sie wurden überarbeitet, um sie trockener zu machen - die Absicht jedes Tests war nicht mehr klar."
Es hört sich so an, als hätten Sie Probleme beim Refactoring. Ich vermute nur, aber wenn es weniger klar ist, heißt das nicht, dass Sie noch mehr Arbeit zu tun haben, damit Sie einigermaßen elegante Tests haben, die vollkommen klar sind?
Aus diesem Grund sind Tests eine Unterklasse von UnitTest. So können Sie gute Testsuiten entwerfen, die korrekt, einfach zu validieren und klar sind.
In früheren Zeiten hatten wir Testwerkzeuge, die verschiedene Programmiersprachen verwendeten. Es war schwierig (oder unmöglich), mit Tests angenehm und einfach zu arbeiten.
Sie haben die volle Leistungsfähigkeit von Python, Java, C # - egal welche Sprache Sie verwenden - also verwenden Sie diese Sprache gut. Sie können einen gut aussehenden Testcode erzielen, der klar und nicht zu redundant ist. Es gibt keinen Kompromiss.
quelle