Sollten wir immer Unit-Test-Bugs verwenden, wenn wir sie korrigieren?

29

Beim Korrigieren von Fehlern wird empfohlen, zunächst einen Test zu schreiben, der mit dem angegebenen Fehler fehlschlägt, und dann den Code zu korrigieren, bis der Test bestanden ist. Dies folgt TDD-Praktiken und soll eine gute Praxis sein, aber ich habe festgestellt, dass es dazu neigt, kryptische Tests zu erstellen, die der Implementierung sehr nahe kommen.

Zum Beispiel hatten wir ein Problem, als ein Auftrag gesendet wurde, einen bestimmten Status erreichte, abgebrochen und erneut versucht wurde. Um diesen Fehler zu reproduzieren, wurde ein umfangreicher Test geschrieben, der Thread-Synchronisation, viele Verspottungen und ähnliches enthielt. Es hat funktioniert, aber jetzt, da ich den Code überarbeite, finde ich es sehr verlockend, dieses Mammut einfach zu entfernen es würde wirklich (wieder) viel Arbeit erfordern, um zum neuen Design zu passen. Und es wird nur eine kleine Funktion in einem bestimmten Fall getestet.

Daher meine Frage: Wie prüft man auf Bugs, die sich nur schwer reproduzieren lassen? Wie vermeiden Sie es, Dinge zu erstellen, die die Implementierung testen und Refactoring und Lesbarkeit beeinträchtigen?

Zonko
quelle
Ist dieser Fehlerfall für das neue Design relevant? Für mich würde ein Teil eines neuen Designs darin bestehen, die Zuverlässigkeit des Designs zu erhöhen, sodass Sie dies möglicherweise als Rechtfertigung für das Entfernen dieses Testfalls heranziehen können, wenn diese Art von Fehler irgendetwas mit einem Fehler im ursprünglichen Design zu tun hatte.
Thymine
Beim Refactor geht es um etwas anderes, und im neuen Design ist es immer noch möglich, den Code geringfügig zu ändern und den Fehler wieder einzuführen, den der Test beobachtet. Ich denke, eine Alternative zum Test wäre ein Kommentar im Code, der sagt: "Nicht damit ficken", aber es klingt nach einer falschen Vorgehensweise: p
Zonko
1
wenn es zu komplex für ein wenig ist, mach es Teil des Integrationstests
Ratschenfreak
Klingt nach einem Integrationstest und nicht nach einem Komponententest. Basierend auf der Tatsache, dass Sie so viel verspotten. Eine allgemeine Regel, die ich gesehen habe, ist, dass Sie keinen Code testen, der mit Komponenten außerhalb Ihrer Codebasis kommuniziert (mit einer Datenbank kommunizieren, aus dem Dateisystem lesen usw.), was sich auch so anhört.
Lucas

Antworten:

27

Ja, im Allgemeinen Sie sollten . Wie bei allen Richtlinien müssen Sie nach bestem Wissen vorgehen, wenn sie gegen andere Richtlinien verstoßen. In diesem Szenario muss der Schweregrad des Fehlers gegen die für die Implementierung des Tests erforderliche Arbeit abgewogen werden, und die Qualität dieses Tests muss auf das Geschäftsproblem ausgerichtet sein und es muss eine Regression des Fehlerzustands festgestellt werden.

Ich würde eher das Schreiben von Tests als das Nichtschreiben von Tests bevorzugen, da Unterbrechungen, die zu Fehlern führen, in der Regel mehr Aufwand verursachen, als nur einen Komponententest zu entwickeln und aufrechtzuerhalten.

Telastyn
quelle
Ich möchte dem mehr Nachdruck verleihen und feststellen, dass es in einer idealen Welt nur dann einen Fehler gibt, wenn ein fehlgeschlagener Komponententest vorliegt, aber für die Kursivschrift +1 und die Feststellung, dass die geschäftlichen Anforderungen Vorrang haben sollten .
Joshua Drake
2
Nun, letztendlich geht es um ein Gleichgewicht zwischen der Zeit, die benötigt wird, um den Test aufrechtzuerhalten, und der Zeit, die ein Anfänger benötigt, um den Fehler zu erkennen und zu korrigieren, wenn er erneut auftritt.
Zonko,
Ich würde es auch vorziehen, den Test zu verallgemeinern, damit er nicht nur den Abbruch und die Wiederholung des Jobs testet, wenn er einen bestimmten Status erreicht, sondern auch den Abbruch und die Wiederholung in jedem Status, in dem sich ein Job befinden könnte.
Old Pro
+1 für "da Unterbrechungen dazu neigen, mehr Aufwand zu verursachen, als nur einen Komponententest zu entwickeln und aufrechtzuerhalten."
Peter K.
16

Ich denke, die beste Vorgehensweise - eine, der ich peinlich zugeben muss, dass ich sie nicht oft folge - besteht darin, einen System- oder Integrationstest zu erstellen, der das in der Produktion festgestellte Problem demonstriert, und dann nach den für das Problem verantwortlichen Einheiten zu suchen. und schreiben Sie dann Unit-Tests für die Units, die das Problem auf Unit-Ebene demonstrieren . Sobald Sie die Einheitentests durchgeführt haben, korrigieren Sie die Einheiten und führen Sie alle Tests durch. Zu diesem Zeitpunkt kann es ratsam sein, den ursprünglichen Test zu verwerfen, da er möglicherweise zerbrechlich und / oder langsam ist. Bewahren Sie die Komponententests jedoch aus Gründen der Regression und der Abdeckung in Ihrer automatisierten Suite auf.

Carl Manaster
quelle
7

Das Schreiben eines Tests zur Feststellung des Fehlers ist eine gute Idee, da Sie damit genau ermitteln können, welche Schritte erforderlich sind, um den Fehler zu reproduzieren, und überprüfen, ob er behoben wurde. Darüber hinaus können diese Tests als Teil von Rauch- oder Regressionstests durchgeführt werden, um sicherzustellen, dass spätere Änderungen keinen alten Fehler in das System zurückgeführt haben.

Das erste, was zu berücksichtigen ist, ist das Niveau des erforderlichen Tests. Möglicherweise ist der Test zur Überprüfung des Fixes auf Systemebene besser geeignet, oder es kann sogar ein manueller Abnahmetest durchgeführt werden. Ich denke, es ist wichtiger, einen Test zu haben, der dokumentiert und verwaltet wird, unabhängig davon, wie er speziell implementiert wurde.

Inwieweit sich Refactoring auf Tests auswirkt, hängt von den spezifischen Merkmalen ab. In einigen Fällen kann eine Umgestaltung (oder irgendeine Art von Arbeit, wie z. B. neue Funktionen) dazu führen, dass die Tests nicht mehr erforderlich sind. Das ursprünglich aufgetretene Problem ist möglicherweise nicht mehr möglich. In diesem Fall ist es möglicherweise ratsam, den Test aus den möglichen Tests zu entfernen, um Ihren Testprozess (automatisiert oder manuell) schlanker zu gestalten. In anderen Fällen gibt es mehrere Methoden zum Durchführen des Tests und das Überprüfen der Funktion auf einer anderen Ebene ist möglicherweise geeigneter. Wenn das Merkmal geringfügig ist, ist der Test möglicherweise überhaupt nicht mehr erforderlich.

Sie können sich auch darauf verlassen, nicht nur zu testen, sondern auch zu protokollieren. Beispiel: Erfassen von Informationen zur Laufzeit (mit je nach Umgebung unterschiedlicher Ausführlichkeit - ausführlicher während des Testens, weniger ausführlich während der Bereitstellung), Erstellen von Profilen für die Anwendung, Erfassen von Speicherauszügen des aktuellen Systemzustands. Wenn Sie gemeinsame Auslöser für das Problem finden, können Sie diese als Leitfaden für Tests auf allen Ebenen verwenden.

Thomas Owens
quelle
5

Ja du solltest.

Schreiben Sie Komponententests für die vorhandene Codebasis. Wenn Sie einen Fehler beheben, müssen Sie sicherstellen, dass Ihr Komponententest fehlschlägt. Dies gibt Ihnen die Gewissheit, dass Sie tatsächlich an einem Fehler arbeiten. Anschließend müssen Sie den Test neu faktorisieren und bestehen, indem Sie den Fehler beheben.

Dies ist jedoch keine TDD-Praxis. In TDD-Tests fahren Sie Ihr Design, aber in Ihrem Fall wurde das Design bereits entschieden.

CodeART
quelle