Unit Testing Anti-Patterns-Katalog

203

Anti-Muster : Es müssen mindestens zwei Schlüsselelemente vorhanden sein, um ein tatsächliches Anti-Muster formal von einer einfachen schlechten Angewohnheit, einer schlechten Praxis oder einer schlechten Idee zu unterscheiden:

  • Einige wiederholte Handlungs-, Prozess- oder Strukturmuster, die zunächst als vorteilhaft erscheinen, aber letztendlich mehr schlimme Konsequenzen als vorteilhafte Ergebnisse haben, und
  • Eine überarbeitete Lösung, die klar dokumentiert, in der Praxis bewiesen und wiederholbar ist.

Stimmen Sie für das TDD-Anti-Pattern ab, das Sie einmal zu oft "in the wild" gesehen haben.
Der Blog-Beitrag von James Carr und verwandte Diskussion über testgetriebene Entwicklung yahoogroup

Wenn du einen 'unbenannten' gefunden hast, poste sie auch. Ein Beitrag pro Anti-Pattern bitte , damit die Stimmen für etwas zählen.

Mein berechtigtes Interesse ist es, die Top-n-Untergruppe zu finden, damit ich sie in naher Zukunft in einer Lunchbox besprechen kann.

Gishu
quelle
Aaron, du scheinst überall zu sein :) Wäre es eine gute Idee, die Tag-Zeilen oder Slogans als Kommentare hinzuzufügen, damit wir weniger scrollen können. Was soll ich sagen?
Gishu
1
Das kommt ziemlich gut an .. danke Jungs und Mädels. Lass sie kommen .. einer der informativsten SO-Beiträge IMHO
Gishu
2
+1 liebe diesen Thread !!! Und die meisten davon sind so wahr und auch vorherrschend!
Chii
Netter Thread, warum ist dieses Community-Wiki aber ???
Quibblesome
2
Weil es eine Art Umfrage ist - du willst keinen Repräsentanten ernten, nur weil du die häufigste Art von Anti-Pattern gepostet hast;)
Gishu

Antworten:

70

Bürger zweiter Klasse - Testcode ist nicht so gut überarbeitet wie Produktionscode, der viel doppelten Code enthält, was die Verwaltung von Tests erschwert.

Ilja Preuß
quelle
67

Die freie Fahrt / Huckepack - James Carr, Tim Ottinger
Anstatt eine neue Testfallmethode zu schreiben, um ein anderes / unterschiedliches Merkmal / eine andere Funktionalität zu testen , wird eine neue Behauptung (und die entsprechenden Aktionen, dh Act-Schritte von AAA) in einem vorhandenen Testfall mitgeführt .

Aaron Digulla
quelle
15
Ja, das ist mein Favorit. Das mache ich die ganze Zeit. Oh ... warte ... du hast gesagt, dass das eine schlechte Sache ist. :-)
Guidoismus
1
Ich bin mir nicht sicher, ob dies ein Anti-Muster ist. Alle Invarianten müssen truenach jedem möglichen Mutator-Aufruf sein. Sie sollten also überprüfen, ob jede Invariante truenach jeder Kombination von Mutator- und Eingabedaten steht, die Sie testen. Sie sollten jedoch die Duplizierung reduzieren und sicherstellen, dass Sie alle Invarianten überprüfen , einschließlich derjenigen, die derzeit keine Testfehler verursachen. Sie stellen sie also alle in eine checkInvariants()Überprüfungsfunktion und verwenden diese in jedem Test. Der Code ändert sich und eine weitere Invariante wird hinzugefügt. Das setzen Sie natürlich auch in die Funktion ein. Aber es ist ein Freerider.
Raedwald
2
@Raedwald - Im Laufe der Zeit stimmt der Testname nicht mehr mit allen getesteten Dingen überein. Außerdem haben Sie aufgrund von Verflechtungstests einige Probleme. Ein Fehler zeigt nicht die genaue Fehlerursache an. Beispiel: Ein kanonisches Beispiel für diesen Test würde so etwas wie eine undurchsichtige Obermenge aller Anordnungsschritte lesen. >> Handeln >> A behaupten >> Noch etwas handeln >> B weitergeben >> Noch etwas handeln >> C behaupten. Nun idealerweise, wenn A und C sind defekt, sollten Sie 2 Testfehler sehen. Mit dem obigen Test würden Sie nur einen sehen, dann reparieren Sie A und beim nächsten Lauf würde es Ihnen sagen, dass jetzt C kaputt ist. Stellen Sie sich nun 5-6 verschiedene Tests vor, die miteinander verschmolzen sind.
Gishu
1
"Der Testname stimmt nicht mehr mit allen getesteten Elementen überein" Nur wenn der Test nach der ursprünglich vorhandenen Post-Bedingung benannt ist. Wenn Sie die Kombination aus Methodenname, Einrichtungsstatus und Eingabedaten (Methodenargumente) benennen, gibt es kein Problem.
Raedwald
"Ein Fehler zeigt nicht die genaue Fehlerursache an." Kein Assertionsfehler zeigt jemals die Ursache eines Fehlers an. Dazu müssen Sie sich eingehend mit den Implementierungsdetails befassen: Debuggen auf einen Regressionsfehler, Kenntnis des Entwicklungsstatus für einige TDD-Arbeiten.
Raedwald
64

Glücklicher Weg

Der Test bleibt auf glücklichen Pfaden (dh erwarteten Ergebnissen), ohne auf Grenzen und Ausnahmen zu testen.

JUnit Antipatterns

Geoglyphe
quelle
Ursache: Entweder übertriebene Zeitbeschränkungen oder offensichtliche Faulheit. Überarbeitete Lösung: Nehmen Sie sich etwas Zeit, um weitere Tests zu schreiben, um die Fehlalarme zu beseitigen. Die letztere Ursache braucht eine Peitsche. :)
Spoike
59

Der lokale Held

Ein Testfall, der von etwas abhängt, das für die Entwicklungsumgebung spezifisch ist, für die er geschrieben wurde, um ausgeführt zu werden. Das Ergebnis ist, dass der Test Entwicklungsboxen weitergibt, aber fehlschlägt, wenn jemand versucht, ihn an einer anderen Stelle auszuführen.

Die versteckte Abhängigkeit

Eng verwandt mit dem lokalen Helden, einem Komponententest, bei dem einige vorhandene Daten vor dem Ausführen des Tests irgendwo ausgefüllt werden müssen. Wenn diese Daten nicht ausgefüllt wurden, schlägt der Test fehl und gibt dem Entwickler nur wenig Aufschluss darüber, was er wollte oder warum… er gezwungen wurde, mehrere Hektar Code zu durchsuchen, um herauszufinden, woher die verwendeten Daten stammen sollten.


Leider viel zu oft mit alten DLLs gesehen, die von nebulösen und vielfältigen INI-Dateien abhängen, die auf einem bestimmten Produktionssystem nicht synchron sind, geschweige denn auf Ihrem Computer vorhanden sind, ohne die drei Entwickler, die für diese DLLs verantwortlich sind, ausführlich zu konsultieren. Seufzer.

Annakata
quelle
Das ist ein schönes Beispiel für das Akronym WOMPC-Entwickler. "Funktioniert auf meinem PC!" (Wird normalerweise gesagt, um Tester von Ihrem Rücken zu bekommen.)
Joris Timmermans
58

Kettenbande

Einige Tests, die in einer bestimmten Reihenfolge ausgeführt werden müssen, dh ein Test ändert den globalen Status des Systems (globale Variablen, Daten in der Datenbank) und der nächste Test hängt davon ab.

Sie sehen dies häufig in Datenbanktests. Anstatt ein Rollback teardown()durchzuführen, schreiben Tests ihre Änderungen in die Datenbank. Eine weitere häufige Ursache ist, dass Änderungen am globalen Status nicht in try / finally-Blöcken eingeschlossen sind, die bereinigen, falls der Test fehlschlägt.

Aaron Digulla
quelle
Dieser ist einfach nur böse. Bricht die Tests müssen unabhängige Vorstellung sein. Aber ich habe an mehreren Stellen darüber gelesen. Vermutlich ist 'populäres TDD' ziemlich durcheinander
Gishu
56

The Mockery
Manchmal kann Spott gut und praktisch sein. Aber manchmal können Entwickler sich selbst verlieren und sich bemühen, das zu verspotten, was nicht getestet wird. In diesem Fall enthält ein Komponententest so viele Mocks, Stubs und / oder Fakes, dass das zu testende System überhaupt nicht getestet wird. Stattdessen werden die von Mocks zurückgegebenen Daten getestet.

Quelle: James Carrs Beitrag.

Gishu
quelle
2
Ich glaube, die Ursache dafür ist, dass Ihre getestete Klasse viel zu viele Abhängigkeiten aufweist. Die überarbeitete Alternative besteht darin, Code zu extrahieren, der isoliert werden kann.
Spoike
@Spoike; Wenn Sie sich in einer mehrschichtigen Architektur befinden, die wirklich von der Rolle der Klasse abhängt; Einige Ebenen weisen tendenziell mehr Abhängigkeiten auf als andere.
Krosenvold
Ich habe kürzlich in einem angesehenen Blog die Erstellung eines Mock-Entity-Setups gesehen, das aus einem Mock-Repository zurückgegeben werden soll. WTF? Warum nicht gleich eine reale Entität instanziieren? Ich selbst wurde gerade von einer verspotteten Schnittstelle verbrannt, auf der meine Implementierung NotImplementedExceptions auslöste.
Thomas Eyde
40

Der stille Fänger - Kelly?
Ein Test, der bestanden wird, wenn eine Ausnahme ausgelöst wird. Auch wenn die tatsächlich auftretende Ausnahme eine andere ist als die vom Entwickler beabsichtigte.
Siehe auch: Secret Catcher

[Test]
[ExpectedException(typeof(Exception))]
public void ItShouldThrowDivideByZeroException()
{
   // some code that throws another exception yet passes the test
}
Gishu
quelle
Das ist knifflig und gefährlich (dh Sie glauben, Sie hätten Code getestet, der bei jeder Ausführung explodiert). Aus diesem Grund versuche ich, sowohl eine Ausnahmeklasse als auch etwas Einzigartiges in der Nachricht genau zu definieren.
Joshua Cheek
34

Der Inspektor
Ein Komponententest, der die Kapselung verletzt, um eine 100% ige Codeabdeckung zu erreichen, aber so viel über die Vorgänge im Objekt weiß, dass jeder Versuch einer Umgestaltung den vorhandenen Test unterbricht und erfordert, dass Änderungen in der Einheit berücksichtigt werden Prüfung.


"Wie teste ich meine Mitgliedsvariablen, ohne sie öffentlich zu machen ... nur zum Testen von Einheiten?"

Gishu
quelle
2
Ursache: Absurdes Vertrauen in White-Box-Tests. Es gibt Tools zum Generieren solcher Tests wie Pex unter .NET. Überarbeitete Lösung: Testen Sie stattdessen das Verhalten. Wenn Sie die Grenzwerte wirklich überprüfen müssen, lassen Sie den Rest von automatisierten Tools generieren.
Spoike
1
Bevor Moq vorbeikam, musste ich mich über spöttische Rahmenbedingungen hinwegsetzen, um meine Verspottungen von Hand zu schreiben. Es war einfach zu einfach, meine Tests an die tatsächliche Implementierung zu binden, was ein Refactoring nahezu unmöglich machte. Ich kann den Unterschied nicht erkennen, außer bei Moq mache ich selten solche Fehler.
Thomas Eyde
34

Übermäßiges Setup - James Carr
Ein Test, der ein umfangreiches Setup erfordert, um überhaupt mit dem Testen zu beginnen. Manchmal werden mehrere hundert Codezeilen verwendet, um die Umgebung auf einen Test mit mehreren beteiligten Objekten vorzubereiten. Dies kann es schwierig machen, wirklich festzustellen, was getestet wird, da das gesamte Setup „gerauscht“ ist. (Src: James Carrs Beitrag )

Gishu
quelle
Ich verstehe, dass ein übermäßiger Testaufbau normalerweise auf a) schlecht strukturierten Code oder b) unzureichende Verspottung hinweist, richtig?
Topher Hunt
Nun, jede Situation könnte anders sein. Dies könnte an einer hohen Kopplung liegen. In der Regel handelt es sich jedoch um eine Überspezifikation, bei der jeder Mitarbeiter im Szenario spezifiziert wird (Scheinerwartungen). Dies koppelt den Test mit der Implementierung und macht sie brüchig. Wenn der Anruf beim Mitarbeiter ein zufälliges Detail des Tests ist, sollte er nicht im Test enthalten sein. Dies hilft auch dabei, den Test kurz und lesbar zu halten.
Gishu
32

Analsonde

Ein Test, der verrückte, illegale oder auf andere Weise ungesunde Methoden verwenden muss, um seine Aufgabe auszuführen, z. B .: Lesen privater Felder mit Javas setAccessible (true) oder Erweitern einer Klasse, um auf geschützte Felder / Methoden zuzugreifen, oder Ausführen des Tests in ein bestimmtes Paket, um darauf zuzugreifen Paket globale Felder / Methoden.

Wenn Sie dieses Muster sehen, verwenden die getesteten Klassen zu viele versteckte Daten.

Der Unterschied zu The Inspector besteht darin, dass die zu testende Klasse versucht, selbst die Dinge zu verbergen, die Sie testen müssen. Ihr Ziel ist es also nicht, eine 100% ige Testabdeckung zu erreichen, sondern überhaupt etwas testen zu können. Stellen Sie sich eine Klasse vor, die nur private Felder hat, eine run()Methode ohne Argumente und überhaupt keine Getter. Es gibt keine Möglichkeit, dies zu testen, ohne gegen die Regeln zu verstoßen.


Kommentar von Michael Borgwardt: Dies ist nicht wirklich ein Test-Antimuster, es ist Pragmatismus, mit Mängeln im zu testenden Code umzugehen. Natürlich ist es besser, diese Mängel zu beheben, aber dies ist bei Bibliotheken von Drittanbietern möglicherweise nicht möglich.

Aaron Digulla: Ich stimme irgendwie zu. Vielleicht ist dieser Eintrag wirklich besser für ein "JUnit HOWTO" -Wiki geeignet und nicht für ein Antipattern. Bemerkungen?

Aaron Digulla
quelle
Ist das nicht dasselbe wie der Inspektor?
Gishu
1
Hmm .. diese Zeile "Die zu testende Klasse versucht, selbst die Dinge zu verbergen, die Sie testen müssen" zeigt einen Machtkampf zwischen der Klasse und dem Test an. Wenn es getestet werden sollte, sollte es irgendwie öffentlich erreichbar sein, über Klassenverhalten / Schnittstelle. Dies riecht irgendwie nach einer Verletzung der Kapselung
Gishu
2
npellow: Maven2 hat dafür ein Plugin, oder?
Aaron Digulla
1
Dies ist nicht wirklich ein Test-Antimuster, es ist Pragmatismus, mit Mängeln im zu testenden Code umzugehen. Natürlich ist es besser, diese Mängel zu beheben, aber dies ist bei Bibliotheken von Drittanbietern möglicherweise nicht möglich.
Michael Borgwardt
1
IDK, es muss eine Art Nebenwirkung haben. Ich würde die Nebenwirkung testen. Sie sind sich nicht sicher, was Sie mit dem Testen der API von Drittanbietern meinen. Ich würde argumentieren, dass Sie diesen Code in Ihren eigenen Code einschließen sollten, den Sie testen können, und diesen Code dann anhand der API von Drittanbietern auf Integrationstest testen. Ich würde keinen Code von Drittanbietern testen.
Joshua Cheek
26

Der Test ohne Namen - Nick Pellow

Der Test, der hinzugefügt wird, um einen bestimmten Fehler im Bug-Tracker zu reproduzieren, und dessen Autor der Meinung ist, rechtfertigt keinen eigenen Namen. Anstatt einen vorhandenen, fehlenden Test zu verbessern, wird ein neuer Test mit dem Namen testForBUG123 erstellt.

Zwei Jahre später, wenn dieser Test fehlschlägt, müssen Sie möglicherweise zuerst versuchen, BUG-123 in Ihrem Bug-Tracker zu finden, um die Absicht des Tests herauszufinden.

npellow
quelle
7
So wahr. Das ist etwas hilfreicher als ein Test namens "TestMethod"
NikolaiDante
8
es sei denn, der Bugtracker ändert sich und Sie verlieren den alten Tracker und seine Problemkennungen ... also bedeutet PROJECT-123 nichts mehr ...
Chii
25

Der langsame Sack

Ein Unit-Test, der unglaublich langsam läuft. Wenn Entwickler loslegen, haben sie Zeit, auf die Toilette zu gehen, etwas zu rauchen oder, schlimmer noch, den Test zu starten, bevor sie am Ende des Tages nach Hause gehen. (Src: James Carrs Beitrag )

aka die Tests, die nicht so häufig ausgeführt werden, wie sie sollten

Gishu
quelle
Einige Tests laufen von Natur aus langsam ab. Wenn Sie diese nicht so oft wie die anderen ausführen möchten, stellen Sie sicher, dass sie mindestens so oft wie möglich auf einem CI-Server ausgeführt werden.
Chris Vest
Dies ist eine offensichtliche Frage, aber was sind die allgemeinsten Möglichkeiten, dies zu beheben?
Topher Hunt
Das scheint zunächst von Vorteil zu sein, oder?
Kev
1
@TopherHunt Normalerweise sind die Tests langsam, da sie eine teure Abhängigkeit aufweisen (dh Dateisystem, Datenbank). Der Trick besteht darin, die Abhängigkeiten zu analysieren, bis Sie das Problem sehen, und dann die Abhängigkeit in den Callstack zu verschieben. Ich schrieb eine Fallstudie, in der meine Schüler ihre Unit-Test-Suite von 77 Sekunden auf 0,01 Sekunden veränderten, indem sie ihre Abhängigkeiten korrigierten
Joshua Cheek
20

Der Schmetterling

Sie müssen etwas testen, das Daten enthält, die sich ständig ändern, z. B. eine Struktur, die das aktuelle Datum enthält, und es gibt keine Möglichkeit, das Ergebnis auf einen festen Wert festzulegen. Der hässliche Teil ist, dass Sie sich überhaupt nicht für diesen Wert interessieren. Es macht Ihren Test nur komplizierter, ohne einen Mehrwert zu schaffen.

Die Fledermaus ihres Flügels kann einen Hurrikan auf der anderen Seite der Welt verursachen. - Edward Lorenz, Der Schmetterlingseffekt

Aaron Digulla
quelle
Was ist das Anti-Muster hier: Wie sieht ein Test wie dieser aus? Gibt es eine Lösung? Gibt es einen fraglichen Vorteil für den zu testenden Code, um eine Abhängigkeit wie System.DateTime.Nowdie einfacheren oder deterministischeren Komponententests herauszufiltern ?
Merlyn Morgan-Graham
1
In Java wäre ein Beispiel das Aufrufen toString()eines Objekts, das die Methode nicht überschreibt. Dadurch erhalten Sie die ID des Objekts, die von der Speicheradresse abhängt. Oder toString()enthält den Primärschlüssel des Objekts, der sich jedes Mal ändert, wenn Sie den Test ausführen. Es gibt drei Möglichkeiten, dies zu beheben: 1. Ändern Sie den Code, den Sie testen, 2. Verwenden Sie Regexp, um die variablen Teile der Testergebnisse zu entfernen, oder 3. Verwenden Sie leistungsstarke Tools, um Systemdienste zu überschreiben, damit sie vorhersehbare Ergebnisse zurückgeben.
Aaron Digulla
Die zugrunde liegende Ursache für dieses Anti-Pattern ist, dass es dem getesteten Code egal ist, wie viel Aufwand es sein könnte, ihn zu testen. Die Laune eines Entwicklers ist also der Flügel des Schmetterlings, der anderswo Probleme verursacht.
Aaron Digulla
19

Der Flackertest (Quelle: Romilly Cocking)

Ein Test, der nur gelegentlich fehlschlägt, nicht zu bestimmten Zeiten, und der im Allgemeinen auf die Rennbedingungen innerhalb des Tests zurückzuführen ist. Tritt normalerweise auf, wenn etwas Asynchrones getestet wird, z. B. JMS.

Möglicherweise ein Super-Set für das Anti-Pattern ' Wait and See ' und das Anti-Pattern ' The Sleeper '.

Der Build ist fehlgeschlagen. Führen Sie den Build einfach erneut aus. - Anonymer Entwickler

Stuart
quelle
@Stuart - ein Video, das man gesehen haben muss, ist "Car Stalled - Try Now!" videosift.com/video/… Dieses Muster könnte auch "Try Now!" oder einfach "The Flakey Test"
npellow
1
Ich habe einmal einen Test für ein PRGN geschrieben, der eine ordnungsgemäße Verteilung sicherstellte. Gelegentlich schlug es zufällig fehl. Stelle dir das vor. :-)
Chris Vest
1
Wäre das nicht ein guter Test? Wenn ein Test jemals fehlschlägt, müssen Sie die Ursache des Problems ermitteln. Ich habe mit jemandem um einen Test gekämpft, der zwischen 21 Uhr und Mitternacht fehlgeschlagen ist. Er sagte, es sei zufällig / zeitweise. Es wurde schließlich auf einen Fehler zurückgeführt, der sich mit Zeitzonen befasste. Stelle dir das vor.
Trenton
@Christian Vest Hansen: Könntest du es nicht säen?
Andrew Grimm
@trenton Es ist nur ein guter Test, wenn die Entwickler sich die Mühe machen können, ihn aufzuspüren, anstatt ihn einfach zu ignorieren (womit sie durchkommen können, da er die meiste Zeit vergeht).
Will Sheppard
19

Warten wir es ab

Ein Test, der einen eingerichteten Code ausführt und dann eine bestimmte Zeit warten muss, bevor er sehen kann, ob der zu testende Code wie erwartet funktioniert. Eine testMethod, die Thread.sleep () oder eine gleichwertige Methode verwendet, ist mit Sicherheit ein "Wait and See" -Test.

In der Regel wird dies angezeigt, wenn der Test Code testet, der ein systemexternes Ereignis wie eine E-Mail, eine http-Anforderung oder das Schreiben einer Datei auf die Festplatte generiert.

Ein solcher Test kann auch ein lokaler Held sein, da er fehlschlägt, wenn er auf einer langsameren Box oder einem überlasteten CI-Server ausgeführt wird.

Das Wait-and-See-Anti-Pattern ist nicht mit The Sleeper zu verwechseln .

npellow
quelle
Hmm .. nun ich benutze so etwas. Wie könnte ich sonst Multithread-Code testen?
Gishu
@Gishu, möchten Sie wirklich mehrere Threads testen, die gleichzeitig ausgeführt werden? Ich versuche nur einen Unit-Test durchzuführen, was auch immer die run () -Methode isoliert tut. Eine einfache Möglichkeit, dies zu tun, besteht darin, run () aufzurufen, das den Unit-Test anstelle von start () blockiert.
npellow
@Gishu verwendet CountDownLatches, Semaphoren, Bedingungen oder ähnliches, damit sich die Threads gegenseitig mitteilen, wann sie zum nächsten Level übergehen können.
Chris Vest
Ein Beispiel: madcoderspeak.blogspot.com/2008/11/… Brew button evt. Der Beobachter fragt in Intervallen ab und löst geänderte Ereignisse aus. In diesem Fall füge ich eine Verzögerung hinzu, damit die Abfragethreads ausgeführt werden können, bevor der Test beendet wird.
Gishu
Ich denke, der Cartoon-Link ist kaputt.
Andrew Grimm
17

Unangemessen gemeinsam genutztes Gerät - Tim Ottinger
Mehrere Testfälle im Testgerät verwenden nicht einmal das Setup / Teardown oder benötigen es. Teilweise aufgrund der Trägheit des Entwicklers beim Erstellen einer neuen Testvorrichtung ... einfacher, einfach einen weiteren Testfall zum Stapel hinzuzufügen

Gishu
quelle
1
Es kann auch sein, dass die getestete Klasse versucht, zu viel zu tun.
Mike Two
16

Der Riese

Ein Komponententest, der, obwohl er das zu testende Objekt gültig testet, Tausende von Zeilen umfassen kann und viele, viele Testfälle enthält. Dies kann ein Indikator dafür sein, dass das zu testende System ein Gottobjekt ist (James Carrs Beitrag).

Ein sicheres Zeichen für diesen ist ein Test, der mehr als ein paar Codezeilen umfasst. Oft ist der Test so kompliziert, dass er Fehler seines eigenen oder schuppigen Verhaltens enthält.

Gishu
quelle
15

Ich werde es glauben, wenn ich einige blinkende GUIs sehe.
Eine ungesunde Fixierung / Besessenheit, die App über ihre GUI zu testen, "genau wie ein echter Benutzer".

Das Testen von Geschäftsregeln über die GUI ist eine schreckliche Form der Kopplung. Wenn Sie Tausende von Tests über die GUI schreiben und dann Ihre GUI ändern, werden Tausende von Tests unterbrochen.
Testen Sie stattdessen nur GUI-Dinge über die GUI und koppeln Sie die GUI mit einem Dummy-System anstelle des realen Systems, wenn Sie diese Tests ausführen. Testen Sie Geschäftsregeln über eine API, an der die GUI nicht beteiligt ist. - Bob Martin

"Sie müssen verstehen, dass Sehen Glauben ist, aber Sie müssen auch wissen, dass Glauben Sehen ist." - Denis Waitley

Gishu
quelle
1
Wenn Sie dachten, dass das Flashen von GUIs falsch ist, habe ich jemanden gesehen, der einen jUnit-Test geschrieben hat, der die GUI gestartet hat und Benutzerinteraktion benötigt, um fortzufahren. Es hing den Rest der Testsuite. Soviel zur Testautomatisierung!
Spoike
Ich bin nicht einverstanden. Das Testen von GUIs ist schwierig, aber sie sind auch eine Fehlerquelle. Sie nicht zu testen ist nur faul.
Ray
3
Der Punkt hier ist, dass Sie keine GUIs testen sollten, sondern dass Sie nicht nur über die GUI testen sollten. Sie können "Headless" -Tests ohne die GUI durchführen. Halten Sie die GUI so dünn wie möglich - verwenden Sie eine Variante von MVP - Sie können dann davonkommen, wenn Sie sie überhaupt nicht testen. Wenn Sie feststellen, dass ständig Fehler in der dünnen GUI-Ebene auftreten, decken Sie diese mit Tests ab. Aber die meiste Zeit finde ich, dass sich die Mühe nicht lohnt. GUI 'Verkabelungsfehler' sind normalerweise einfacher zu beheben ...
Gishu
@Spoike: Geführte manuelle Tests sind weder schlecht noch verwenden sie jUnit (oder ein anderes Framework für Komponententests), um automatisierte Tests durchzuführen, die keine Komponententests sind. Sie sollten diese einfach nicht in dasselbe Projekt einfügen oder wie Komponententests behandeln (z. B. ständig ausführen oder nach jedem Build).
Merlyn Morgan-Graham
1
@ MerlynMorgan-Graham Ich stimme zu, und ich wollte nicht, dass Sie die GUI nicht testen sollten. Die Überzeugung der Teammitglieder, dass es in Ordnung sei, geführte manuelle Tests mit automatischen zu mischen, hat mich beunruhigt. Ich habe später herausgefunden, dass es eine hervorragende Möglichkeit war, alle, die nicht an TDD gewöhnt sind, dazu zu bringen, die Verwendung einzustellen. Ich finde, dass das Mischen von Funktionstests (die flüchtig sind) mit Komponententests (die stabil sein sollen) schlecht ist, wenn Sie dem TDD-Prozess folgen möchten.
Spoike
14

Der Schläfer, auch bekannt als Vesuv - Nick Pellow

Ein Test, der zu einem bestimmten Zeitpunkt und Datum in der Zukunft fehlschlagen soll. Dies wird häufig durch die Überprüfung falscher Grenzen beim Testen von Code verursacht, der ein Datums- oder Kalenderobjekt verwendet. Manchmal schlägt der Test fehl, wenn er zu einer bestimmten Tageszeit ausgeführt wird, z. B. um Mitternacht.

'The Sleeper' ist nicht mit dem Anti-Pattern ' Wait And See ' zu verwechseln .

Dieser Code wird lange vor dem Jahr 2000 ersetzt worden sein - viele Entwickler im Jahr 1960

npellow
quelle
Ich würde dies lieber einen ruhenden Vulkan nennen :) .. aber ich weiß, wovon Sie sprechen .. zB ein Datum, das zum Zeitpunkt des Schreibens als zukünftiges Datum für einen Test ausgewählt wurde, wird zu einem gegenwärtigen / vergangenen Datum, wenn dieses Datum geht vorbei .. den Test zu brechen. Könnten Sie ein Beispiel posten, um dies zu veranschaulichen.
Gishu
@Gishu - +1. Ich dachte das Gleiche, konnte mich aber nicht zwischen den beiden entscheiden. Ich habe den Titel aktualisiert, um dies ein wenig klarer zu machen;)
npellow
11

Der tote Baum

Ein Test, bei dem ein Stub erstellt wurde, der Test jedoch nicht geschrieben wurde.

Ich habe dies tatsächlich in unserem Produktionscode gesehen:

class TD_SomeClass {
  public void testAdd() {
    assertEquals(1+1, 2);
  }
}

Ich weiß nicht einmal, was ich davon halten soll.

Reverend Gonzo
quelle
8
:) - auch als Process Compliance Backdoor bekannt.
Gishu
1
Wir hatten kürzlich ein Beispiel dafür in einem Test und einer Testmethode, die wiederholt überarbeitet wurden. Nach einigen Iterationen wurde der Test zu einem Aufruf der zu testenden Methode. Und weil die Methode jetzt ungültig war, waren keine Aussagen zu machen. Im Grunde genommen stellte der Test nur sicher, dass die Methode keine Ausnahme auslöste. Es war egal, ob es tatsächlich etwas Nützliches oder Richtiges tat. Ich fand es in der Codeüberprüfung und fragte: "Also ... was testen wir hier überhaupt?"
Marvo
11

habe heute etwas davon mitbekommen:

Wet Floor :
Der Test erstellt Daten, die irgendwo gespeichert bleiben, aber der Test wird nach Abschluss nicht bereinigt. Dies führt dazu, dass Tests (der gleiche Test oder möglicherweise andere Tests) bei nachfolgenden Testläufen fehlschlagen .

In unserem Fall hat der Test eine Datei im Verzeichnis "temp" mit den Berechtigungen des Benutzers, der den Test zum ersten Mal ausgeführt hat, herumliegen lassen. Wenn ein anderer Benutzer versucht hat, auf derselben Maschine zu testen: Ausleger. In den Kommentaren auf James Carrs Website bezeichnete Joakim Ohlrogge dies als "Sloppy Worker" und es war Teil der Inspiration für "Generous Leftovers". Ich mag meinen Namen besser (weniger beleidigend, vertrauter).

Zac Thompson
quelle
Sie können die temporäre Ordnerregel von junit verwenden, um nasse Böden zu vermeiden.
DaveFar
Diese Art bezieht sich auf ein Continuous Integration Anti-Pattern. In CI sollte jeder Entwickler über seinen eigenen Arbeitsbereich und seine eigenen Ressourcen verfügen, und die Build-Maschine sollte auch eine eigene Umgebung sein. Dann vermeiden Sie Dinge wie Berechtigungsprobleme (oder Sie verstecken sie am Ende, damit sie nur in der Produktion auftauchen.)
Marvo
11

Der Kuckuck - Frank Carver
Ein Komponententest, der sich in einem Testfall mit mehreren anderen befindet und denselben (möglicherweise langwierigen) Einrichtungsprozess wie die anderen Tests im Testfall durchführt, dann jedoch einige oder alle Artefakte aus dem Setup verwirft und schafft seine eigenen.
Erweitertes Symptom für: Unangemessen freigegebenes Gerät

Gishu
quelle
10

The Secret Catcher - Frank Carver
Ein Test, der auf den ersten Blick keine Tests durchführt, da keine Aussagen vorliegen. Aber "Der Teufel steckt im Detail". Der Test basiert wirklich auf einer Ausnahme, die ausgelöst wird, und erwartet, dass das Testframework die Ausnahme erfasst und dem Benutzer als Fehler meldet.

[Test]
public void ShouldNotThrow()
{
   DoSomethingThatShouldNotThrowAnException();
}
Gishu
quelle
2
Dies kann meiner Meinung nach tatsächlich ein gültiger Test sein - insbesondere als Regressionstest.
Ilja Preuß
Es tut mir leid, dass ich dies wieder mit Silent Catcher verwechselt habe ... Unit-Tests sollten klar sagen, was getestet wird, anstatt zu sagen, dass dies funktionieren sollte. (+1 tp etwas ist besser als nichts. Besonders wenn Sie sich in einer alten Regression befinden Land)
Gishu
1
Bei solchen Tests fange ich zumindest Exception ab und ordne sie einer Variablen zu. Dann behaupte ich nicht null.
Thomas Eyde
4
Einige Frameworks haben eine Assert.DoesNotThrow(SomeDelegateType act)Stilzusicherung, die in solchen Fällen speziell verwendet werden kann. Ich finde das weniger grob als einen Testfall, der erfolgreich ist, wenn ein Konstruktor nicht null zurückgibt, aber fehlschlägt, wenn der Konstruktor wirft. Ein Konstruktor gibt niemals null zurück. (Hinweis: Gilt nur für Sprachen, in denen ein Konstruktor garantiert nicht null zurückgibt.)
Merlyn Morgan-Graham
10

Der Umweltvandal

Ein "Unit" -Test, der für verschiedene "Anforderungen" in seine Umgebung gelangt und Umgebungsvariablen / -ports verwendet und festlegt. Das gleichzeitige Ausführen von zwei dieser Tests führt zu Ausnahmen für nicht verfügbare Ports usw.

Diese Tests werden zeitweise durchgeführt und lassen Entwickler Dinge wie "Führen Sie es einfach noch einmal aus" sagen.

Eine Lösung, die ich gesehen habe, besteht darin, zufällig eine zu verwendende Portnummer auszuwählen. Dies verringert die Möglichkeit eines Konflikts, löst das Problem jedoch eindeutig nicht. Wenn Sie können, verspotten Sie den Code immer so, dass er die nicht gemeinsam nutzbare Ressource nicht tatsächlich zuweist.

gcrain
quelle
@ gcrain .. Tests sollten deterministisch sein. IMO wäre ein besserer Ansatz, einen "im Team bekannten" Port zum Testen und Bereinigen vor und nach dem Test korrekt zu verwenden, so dass er immer verfügbar ist ...
Gishu
1
@gishu - Das Problem ist nicht, dass es keine Setup () - und Teardown () -Methoden gibt, die mit diesen Ports umgehen können. Das Problem besteht beispielsweise darin, dass ein CI-Server ausgeführt wird und mehrere Versionen des Tests gleichzeitig ausgeführt werden und versucht wird, dieselben im Test fest
codierten
10

Der Turing-Test

Ein Testfall, der automatisch von einem teuren Tool generiert wird, das viele, viele Aussagen aus der zu testenden Klasse mithilfe einer zu cleveren Datenflussanalyse enthält. Lullt Entwickler in ein falsches Gefühl des Vertrauens, dass ihr Code gut getestet ist, und entbindet sie von der Verantwortung, qualitativ hochwertige Tests zu entwerfen und aufrechtzuerhalten. Wenn das Gerät die Tests für Sie schreiben kann, warum kann es dann nicht den Finger herausziehen und die App selbst schreiben?

Hallo Dummkopf. - Der intelligenteste Computer der Welt für einen neuen Lehrling (aus einem alten Amiga-Comic).

bhumphreys
quelle
10

Der Vierzig-Fuß-Pol-Test

Diese Tests haben Angst, der Klasse, die sie testen möchten, zu nahe zu kommen. Sie wirken auf Distanz, getrennt durch unzählige Abstraktionsebenen und Tausende von Codezeilen von der Logik, die sie überprüfen. Als solche sind sie extrem spröde und anfällig für alle möglichen Nebenwirkungen, die auf der epischen Reise von und zur interessierenden Klasse auftreten.

bhumphreys
quelle
9

Doppelgänger

Um etwas zu testen, müssen Sie Teile des zu testenden Codes in eine neue Klasse mit demselben Namen und Paket kopieren und Klassenpfadmagie oder einen benutzerdefinierten Klassenladeprogramm verwenden, um sicherzustellen, dass er zuerst sichtbar ist (damit Ihre Kopie ausgewählt wird) oben).

Dieses Muster weist auf eine ungesunde Anzahl versteckter Abhängigkeiten hin, die Sie mit einem Test nicht kontrollieren können.

Ich sah sein Gesicht an ... mein Gesicht! Es war wie ein Spiegel, aber mein Blut gefror.

Aaron Digulla
quelle
7

Die Mutter Henne - Frank Carver
Ein gängiges Setup, das weit mehr kann, als die eigentlichen Testfälle benötigen. Erstellen Sie beispielsweise alle Arten komplexer Datenstrukturen, die mit scheinbar wichtigen und eindeutigen Werten gefüllt sind, wenn die Tests nur das Vorhandensein oder Fehlen von etwas bestätigen.
Erweitertes Symptom für: Unangemessen freigegebenes Gerät

Ich weiß nicht, was es tut ... Ich füge es trotzdem hinzu, nur für den Fall. - Anonymer Entwickler

Gishu
quelle
7

Der Test alles

Ich kann nicht glauben, dass dies bisher nicht erwähnt wurde, aber Tests sollten nicht gegen das Prinzip der Einzelverantwortung verstoßen .

Ich bin so oft darauf gestoßen, dass Tests, die gegen diese Regel verstoßen, per Definition ein Albtraum sind.

thegreendroid
quelle
6

Line Hitter

Auf den ersten Blick deckt Tests alles ab und die Tools zur Codeabdeckung bestätigen dies zu 100%. In Wirklichkeit treffen Tests jedoch nur Code ohne Ausgabeanalysen.

Coverage-vs-Reachable-Code

Ruslan Dzhabbarov
quelle