Hinzufügen von Komponententests zum Legacy-Code [geschlossen]

78

Haben Sie jemals nachträglich Unit-Tests zum Legacy-Code hinzugefügt? Wie kompliziert war Code und wie schwierig war es, alles zu stummeln und zu verspotten? Hat sich das Endergebnis gelohnt?

BuckeyeSoftwareGuy
quelle
4
Ich werde "Effektiv mit Legacy-Code arbeiten" auschecken. Hoffentlich gibt es mir einige gute Hinweise, wie man Wrapper für all diese statischen Abhängigkeiten schreibt!
BuckeyeSoftwareGuy
Werfen Sie einen Blick auf Rhino Mocking und TDD mit Legacy-Code
LCJ

Antworten:

57

Ich habe festgestellt, dass der beste Weg darin besteht, die Komponententests schrittweise hinzuzufügen und nicht nur einzuspringen und zu sagen, dass wir die Anwendung jetzt einem Komponententest unterziehen werden.

Wenn Sie also den Code berühren möchten, um Fehler zu beheben oder umzugestalten, schreiben Sie zuerst die Komponententests. Bei Fehlern helfen Unit-Tests zu beweisen, wo das Problem liegt, da Sie es duplizieren können.

Beim Refactoring möchten Sie Unit-Tests schreiben, stellen jedoch möglicherweise fest, dass der Test nicht geschrieben werden kann. Daher müssen Sie möglicherweise eine hohe Ebene finden, die die zu refactoring-Funktion aufruft, und diesen Teil Unit-testen. Schreiben Sie dann beim Umgestalten der Angriffsfunktion Ihre Tests, damit Sie sicherstellen können, dass sie ordnungsgemäß funktioniert.

Es gibt keine einfache Möglichkeit, dies zu tun.

Diese Frage kann bei weiteren Vorschlägen hilfreich sein. Wie führen Sie Unit-Tests in eine große Legacy-Codebasis (C / C ++) ein?

James Black
quelle
8
+1 für das schrittweise Hinzufügen der Tests.
TrueWill
42

Michael Feathers Buch "Effektiv mit Legacy-Code arbeiten" ist ein ganzes Buch, das dieses Thema behandelt. Michael gibt an, dass es oft zu schwierig ist, Tests für Legacy-Code einzuführen, da dieser nicht so strukturiert ist, dass er testbar ist. Was ich am meisten aus dem Buch herausgeholt habe, waren ein paar Muster mit den Namen "Sprout-Funktionen" und "Sprout-Klassen". Eine Sprossenfunktion kapselt die Änderung, die Sie im Code vornehmen müssen. Sie testen dann nur diese Funktionen. Die Sprout-Klasse ist dieselbe Idee, außer dass die neue Funktionalität in einer Klasse enthalten ist.

Phillip Ngan
quelle
10

Ja, und es ist im Allgemeinen schmerzhaft. Ich musste stattdessen oft Integrationstests schreiben.

Das Buch The Art of Unit Testing enthält hierzu einige gute Ratschläge. Es wird auch das Buch "Effektiv mit Legacy-Code arbeiten" empfohlen . Letzteres habe ich noch nicht gelesen, aber es liegt auf meinem Stapel.

EDIT: Aber ja, auch eine minimale Codeabdeckung hat sich gelohnt. Es gab mir Vertrauen und ein Sicherheitsnetz für die Überarbeitung des Codes.

EDIT: Ich habe Working Effective with Legacy Code gelesen und es ist ausgezeichnet.

TrueWill
quelle
4
+1 für "Effektiv mit Legacy-Code arbeiten": voller guter Ratschläge; Tatsächlich lohnt es sich, auch für Umgebungen auf der grünen Wiese zu lesen, ebenso wie eine großartige Ressource zum Erstellen von Code für Testbarkeit.
Itowlson
1
+1 für die Idee, Komponententests mit Integrationstests zu ersetzen. Bei richtiger Verspottung sind die ersteren ziemlich oft gut genug
DVK
6

Schauen Sie sich auch den neuen Ansatz im Bereich des Testens älterer Codeeinheiten an - das Asis-Projekt , das vom ApprovalTests- Projekt inspiriert ist und seine Schlüsselkonzepte teilt.

Wie in diesem Artikel zum ApprovalTests-Ansatz erwähnt :

Oft haben Sie ein riesiges Legacy-Code-Projekt, in dem Sie überhaupt keine Tests haben, aber Sie müssen den Code ändern, um eine neue Funktion oder einen Refactor zu implementieren. Das Interessante an Legacy-Code ist: Es funktioniert! Es funktioniert seit Jahren, egal wie es geschrieben ist. Und das ist ein sehr großer Vorteil dieses Codes. Mit Genehmigungen können Sie mit nur einem Test alle möglichen Ausgaben (HTML, XML, JSON, SQL oder welche Ausgabe auch immer) abrufen und genehmigen, weil Sie wissen - es funktioniert! Nachdem Sie einen solchen Test abgeschlossen und das Ergebnis genehmigt haben, sind Sie mit einem Refactoring wirklich viel sicherer, da Sie jetzt alle vorhandenen Verhaltensweisen "gesperrt" haben.

Beim Asis-Tool geht es genau darum, den Legacy-Code zu erhalten, indem Charakterisierungstests automatisch erstellt und ausgeführt werden.

Weitere Informationen finden Sie unter

zavg
quelle
Wie hat das nicht mehr Upvotes? Wenn das Repo das tut, was es behauptet, sollte dies die ausgewählte Antwort sein.
lolololol ol
Befasst es sich übrigens mit Nebenwirkungen in Funktionen? Auch möglich, dieses Problem zu lösen?
lolololol ol
5

Eine Alternative zu Komponententests, die auch in Effektives Arbeiten mit Legacy-Code eingeführt wurden, sind Charakterisierungstests . Ich hatte interessante Ergebnisse mit solchen Tests. Sie sind einfacher einzurichten als Unit-Tests, wenn Sie von einem Punkt aus testen, als getestet werden können (Naht genannt). Der Nachteil ist, dass Sie bei einem fehlgeschlagenen Test weniger Hinweise auf den Ort des Problems haben, da der zu testende Bereich viel größer sein kann als bei Komponententests. Protokollierung hilft hier.


Ein Unit-Test-Framework wie das der xUnit-Familie kann zum Schreiben von Charakterisierungstests verwendet werden.

In solchen Tests, die nach den Fakten geschrieben wurden, überprüfen Behauptungen das aktuelle Verhalten des Codes. Im Gegensatz zu Unit-Tests beweisen sie nicht, dass der Code korrekt ist, sondern legen lediglich das aktuelle Verhalten des Codes fest (charakterisieren).

Der Prozess ist ähnlich wie beim TDD:

  • Schreiben Sie einen Test für einen Teil des Codes
  • Führen Sie es aus - scheitern Sie
  • Korrigieren Sie den Test anhand des beobachteten Verhaltens des Codes
  • führe es aus - pass
  • wiederholen

Die Tests schlagen fehl, wenn Sie das externe Verhalten des Codes ändern. Externes Verhalten des Codes? Klingt vertraut ? Ja, hier sind wir. Jetzt können Sie den Code umgestalten.

Offensichtlich hängt das Risiko von der Abdeckung der Charakterisierungstests ab.

Philant
quelle
5

Schauen Sie sich die kostenlose Open-Source-Dienstprogrammbibliothek ApprovalTests an . Wenn Sie ein .NET-Entwickler sind, hat der Ersteller Llewellyn Falco eine Reihe von Videos erstellt, die zeigen, wie er ApprovalTests verwendet, um Unit-Tests für neuen und älteren Code zu verbessern.

Lynn Langit
quelle
4

Wenn Sie vorhaben, den Legacy-Code umzugestalten, ist das Erstellen dieser Komponententests ein Muss. Machen Sie sich keine Sorgen über Verspottung oder Stubbing - machen Sie sich keine Sorgen über das Testen der Ein- und Ausgänge des Systems, damit Ihre Änderungen oder Umgestaltungsbemühungen die aktuelle Funktionalität nicht beeinträchtigen.

Ich werde Sie nicht anlügen, das Nachrüsten von Unit-Tests auf Legacy-Code ist schwierig - aber es lohnt sich.

Andrew Hare
quelle
Ich habe angefangen, Komponententests für den Legacy-Code zu erstellen, an dem ich gearbeitet habe. Ich habe jedoch festgestellt, dass ich Integrationstests geschrieben habe, keine Komponententests, weil ich tatsächliche Daten erstelle und sie in die Datenbank einfüge. Ich sehe keine Möglichkeit, reine Mocks und Stubs für diesen Legacy-Code zu erstellen, da er überhaupt nicht zum Testen strukturiert ist.
Vin Shahrdar
1

Ich habe einige Zeit gesprochen vor etwa Idee der Reversed Tests Pyramide in Legacy - Code bei XPDays http://xpdays.com.ua/archive/xp-days-ukraine-2012/materials/legacy-code/

Diese Präsentation sollte die Frage beantworten, warum es manchmal so wichtig ist, mit Integrations- / Funktions- oder sogar Akzeptanztests auf hoher Ebene zu beginnen, wenn mit Legacy-Code gearbeitet wird. Und dann langsam, Schritt für Schritt, Unit-Tests einführen. Es gibt keine Codebeispiele - sorry, aber Sie finden einige davon in Michaels Feathers Buch "Effektiv mit Legacy-Code arbeiten".

Sie können auch Legacy Code Retreat http://www.jbrains.ca/legacy-code-retreat überprüfen und nach diesem Meeting in Ihrer Nähe suchen.

streser
quelle