Ich werde damit beauftragt, eine Legacy-Anwendung unter Unit-Test zu stellen. Zunächst einige Hintergrundinformationen zur Anwendung: Es handelt sich um eine Java-RCP-Codebasis mit 600.000 LOC mit diesen Hauptproblemen
- massive Code-Vervielfältigung
- Keine Kapselung, die meisten privaten Daten sind von außen zugänglich, einige der Geschäftsdaten wurden auch als Singletons erstellt, sodass sie nicht nur von außen, sondern auch von überall aus geändert werden können.
- Keine Abstraktionen (z. B. kein Geschäftsmodell, Geschäftsdaten werden in Object [] und double [] [] gespeichert), also kein OO.
Es gibt eine gute Regressionstestsuite und ein effizientes QA-Team testet und findet Fehler. Ich kenne die Techniken, wie man es aus klassischen Büchern, z. B. Michael Feathers, testen kann, aber das ist zu langsam. Da es ein funktionierendes Regressionstestsystem gibt, habe ich keine Angst, das System aggressiv umzugestalten, damit Komponententests geschrieben werden können.
Wie soll ich anfangen, das Problem anzugreifen, um schnell eine Berichterstattung zu erhalten , damit ich dem Management Fortschritte zeigen kann (und tatsächlich anfange, aus dem Sicherheitsnetz der JUnit-Tests Geld zu verdienen)? Ich möchte keine Tools zum Generieren von Regressionstestsuiten verwenden, z. B. AgitarOne, da diese Tests nicht prüfen, ob etwas korrekt ist.
quelle
Antworten:
Ich glaube, es gibt zwei Hauptachsen, entlang derer Code platziert werden kann, wenn es um die Einführung von Komponententests geht: A) Wie prüfbar ist der Code? und B) wie stabil ist es (dh wie dringend braucht es Tests)? Betrachtet man nur die Extreme, ergeben sich 4 Kategorien:
Kategorie 1 ist der naheliegende Einstieg, bei dem Sie mit relativ wenig Arbeit viel profitieren können. Kategorie 2 ermöglicht es Ihnen, Ihre Abdeckungsstatistik schnell zu verbessern (gut für die Moral) und mehr Erfahrung mit der Codebasis zu sammeln, während Kategorie 3 mehr (oft frustrierende) Arbeit ist, aber auch mehr Nutzen bringt. Was Sie als Erstes tun sollten, hängt davon ab, wie wichtig Moral- und Abdeckungsstatistiken für Sie sind. Kategorie 4 ist wahrscheinlich keine Mühe wert.
quelle
Ich habe viel Erfahrung in der Arbeit mit älteren Systemen (allerdings nicht mit Java), die viel größer sind als diese. Ich hasse es, der Überbringer von schlechten Nachrichten zu sein. Ihr Problem ist die Größe Ihres Problems. Ich vermute, Sie haben es unterschätzt.
Das Hinzufügen von Regressionstests zum Legacy-Code ist ein langsamer und teurer Prozess. Viele Anforderungen sind nicht gut dokumentiert - ein Bugfix hier, ein Patch dort und bevor Sie es wissen, definiert die Software ihr eigenes Verhalten. Wenn keine Tests durchgeführt werden, bedeutet dies, dass nur die Implementierung ausgeführt werden muss. Es sind keine Tests erforderlich, um die im Code implementierten impliziten Anforderungen in Frage zu stellen.
Wenn Sie versuchen, schnell Berichterstattung zu erhalten, werden Sie wahrscheinlich den Job beschleunigen, zur Hälfte backen und scheitern. Die Tests decken das Offensichtliche nur teilweise und die tatsächlichen Probleme nur unzureichend ab. Sie werden überzeugen, dass es sich nicht lohnt, genau die Manager zu überzeugen, die Sie an Unit Testing verkaufen möchten, dass dies nur eine weitere Silberkugel ist, die nicht funktioniert.
Meiner Meinung nach ist der beste Ansatz, Sie auf Tests auszurichten. Verwenden Sie Metriken, Bauchgefühl und Fehlerprotokollberichte, um 1% oder 10% des Codes zu identifizieren, der die meisten Probleme verursacht. Schlagen Sie diese Module hart und ignorieren Sie den Rest. Versuchen Sie nicht zu viel zu tun, weniger ist mehr.
Ein realistisches Ziel ist "Seit wir UT implementiert haben, ist die Defekteinfügung in zu testenden Modulen auf x% derjenigen gesunken, die nicht unter UT sind" (idealerweise ist x eine Zahl <100).
quelle
Ich erinnere mich an das Sprichwort, dass ich mir keine Sorgen um das Scheunentor machen soll, wenn das Pferd bereits durchgebrannt ist.
Die Realität ist, dass es wirklich keine kostengünstige Möglichkeit gibt, eine gute Testabdeckung für ein Altsystem zu erhalten, schon gar nicht in einem kurzen Zeitraum. Wie MattNz bereits erwähnte, wird dies ein sehr zeitaufwendiger und letztendlich extrem kostspieliger Prozess sein. Mein Bauch sagt mir, dass Sie, wenn Sie versuchen, das Management zu beeindrucken, wahrscheinlich einen neuen Wartungs-Alptraum schaffen werden, weil Sie versuchen, zu schnell zu zeigen, ohne die Anforderungen zu verstehen, auf die Sie testen möchten.
Wenn Sie den Code erst einmal geschrieben haben, ist es realistisch gesehen fast zu spät, um die Tests effektiv zu schreiben, ohne das Risiko, dass Sie etwas Wichtiges verpassen. Auf der anderen Seite könnte man sagen, dass einige Tests besser sind als keine Tests, aber wenn dies der Fall ist, müssen die Tests selbst zeigen, dass sie dem gesamten System einen Mehrwert verleihen.
Mein Vorschlag wäre, sich die Schlüsselbereiche anzusehen, in denen Sie das Gefühl haben, dass etwas "kaputt" ist. Damit meine ich, es könnte furchtbar ineffizienter Code sein, oder Sie können nachweisen, dass die Wartung bisher sehr kostspielig war. Dokumentieren Sie die Probleme und verwenden Sie diese als Ausgangspunkt, um eine Teststufe einzuführen, die Ihnen hilft, das System zu verbessern, ohne einen massiven Neuentwicklungsaufwand in Kauf zu nehmen. Hier geht es darum, dass Sie nicht mit den Tests aufholen, sondern Tests einführen, die Sie bei der Lösung bestimmter Probleme unterstützen. Überprüfen Sie nach einiger Zeit, ob Sie die vorherigen Kosten für die Wartung dieses Codeabschnitts und den aktuellen Aufwand für die von Ihnen mit den unterstützenden Tests angewendeten Fixes messen und unterscheiden können.
Denken Sie daran, dass das Management mehr an den Kosten / Nutzen interessiert ist und wie sich dies direkt auf die Kunden und letztendlich auf das Budget auswirkt. Sie sind nie daran interessiert, etwas zu tun, nur weil es das Beste ist, wenn Sie nicht nachweisen können, dass es ihnen einen Nutzen bringt, der für sie von Interesse ist. Wenn Sie nachweisen können, dass Sie das System verbessern und eine gute Testabdeckung für die derzeit von Ihnen ausgeführte Arbeit erhalten, ist dies für das Management eher eine effiziente Anwendung Ihrer Bemühungen. Dies könnte es Ihnen möglicherweise ermöglichen, zu argumentieren, dass Sie Ihre Bemühungen auf andere Schlüsselbereiche ausdehnen, ohne entweder ein vollständiges Einfrieren der Produktentwicklung zu fordern, oder noch schlimmer, es ist fast unmöglich, sich für ein Umschreiben auszusprechen!
quelle
Eine Möglichkeit, die Abdeckung zu verbessern, besteht darin, weitere Tests zu schreiben.
Eine andere Möglichkeit besteht darin, die Redundanz in Ihrem Code so zu verringern, dass vorhandene Tests tatsächlich redundanten Code abdecken, der derzeit nicht abgedeckt ist.
Stellen Sie sich vor, Sie haben 3 Codeblöcke, a, b und b ', wobei b' ein Duplikat von B ist (exakte oder fast unpassende Kopie), und Sie haben Deckung über a und b, aber nicht b 'mit Test T.
Wenn Sie die Codebasis refaktorieren, um b 'zu eliminieren, indem Sie die Gemeinsamkeit von b und b' als B extrahieren, sieht die Codebasis jetzt wie folgt aus: a, b0, B, b'0, wobei b0 den nicht gemeinsam genutzten Code mit b'0 enthält, und umgekehrt. umgekehrt, und sowohl b0 als auch b'0 sind viel kleiner als B und rufen / verwenden B auf.
Jetzt hat sich die Funktionalität des Programms nicht geändert, und es wurde auch kein Test T ausgeführt, sodass wir T erneut ausführen können und erwarten, dass es erfolgreich ist. Der Code, der jetzt behandelt wird, ist a, b0 und B, aber nicht b'0. Die Codebasis ist kleiner geworden (b'0 ist kleiner als b '!) Und wir decken immer noch das ab, was wir ursprünglich abgedeckt haben. Unser Deckungsgrad ist gestiegen.
Dazu müssen Sie b, b 'und idealerweise B finden, um Ihr Refactoring zu ermöglichen. Unser CloneDR Tool kann dies für viele Sprachen tun, insbesondere für Java. Sie sagen, Ihre Codebasis enthält viele doppelte Codes. Dies könnte ein guter Weg sein, um es zu Ihrem Vorteil anzugehen.
Seltsamerweise erweitert der Akt des Findens von b und b 'häufig Ihren Wortschatz über die abstrakten Ideen, die das Programm implementiert. Während das Tool keine Ahnung hat, was b und b 'tun, gibt die bloße Isolierung aus dem Code, die eine einfache Konzentration auf den Inhalt von b und b' ermöglicht, Programmierern oft eine sehr gute Vorstellung davon, welche Abstraktion B_abstract der geklonte Code implementiert . Dies verbessert auch Ihr Verständnis des Codes. Vergewissern Sie sich, dass Sie B einen guten Namen geben, wenn Sie darauf verzichten, um eine bessere Testabdeckung und ein besser wartbares Programm zu erhalten.
quelle