Best Practices zum Nachrüsten von Legacy-Code mit automatisierten Tests

22

Ich werde die Aufgabe übernehmen, eine bereits definierte Schnittstelle (eine Reihe von C ++ - Header-Dateien) in einer relativ großen und alten Codebasis neu zu implementieren. Zuvor möchte ich eine möglichst vollständige Testabdeckung haben, damit ich Implementierungsfehler so früh und einfach wie möglich erkennen kann. Das Problem ist, dass die bereits vorhandene Codebasis nicht einfach zu testen ist, da sie (sehr) große Klassen und Funktionen, einen hohen Kopplungsgrad, Funktionen mit (vielen) Nebenwirkungen usw. enthält.

Es wäre schön, von früheren Erfahrungen mit ähnlichen Aufgaben und einigen guten und konkreten Tipps zu hören, wie Sie automatisierte Tests (Einheiten, Integrationen, Regressionen usw.) in Ihren Legacy-Code nachrüsten.

tjansson
quelle
1
Schritt 1: Stapelüberlauf suchen. Die Frage wurde gestellt. Viele, viele Male.
S.Lott

Antworten:

20

Lassen Sie sich zunächst von Michael Feathers Effektiv mit Legacy-Code arbeiten und lesen Sie ihn - er ist eine unverzichtbare Hilfe für solche Aufgaben.

Dann ein paar Notizen:

  • Haben Sie eine genaue Spezifikation / einen genauen Vertrag für die Schnittstelle oder haben Sie praktisch nur die vorhandene Implementierung als "Spezifikation"? Im ersteren Fall ist es einfacher, ein vollständiges Neuschreiben von Grund auf durchzuführen, im letzteren Fall ist es schwierig bis unmöglich.
  • Wenn Sie die Schnittstelle erneut implementieren möchten, ist es am sinnvollsten, Tests nur für die Schnittstelle zu schreiben. Natürlich ist dies kein Unit-Test im eigentlichen Sinne, sondern ein Funktions- / Abnahmetest, aber ich bin kein Purist :-) Diese Tests sind jedoch wiederverwendbar und ermöglichen es Ihnen, die Ergebnisse der beiden Implementierungen direkt nebeneinander zu vergleichen .
  • Insgesamt würde ich es vorziehen, den vorhandenen Code umzugestalten, anstatt ihn von Grund auf neu zu schreiben, es sei denn, er ist absolut nicht zu warten. (Aber wie schreibt man in diesem Fall überhaupt Unit-Tests dagegen?) Lesen Sie diesen Beitrag von Joel, um eine ausführlichere Diskussion zu diesem Thema zu erhalten. Wenn Sie eine Reihe von Abnahmetests für die Benutzeroberfläche erstellt haben, erhalten Sie ein dünnes, aber nützliches Sicherheitsnetz, anhand dessen Sie den vorhandenen Code vorsichtig überarbeiten können, um die Einheit testbar zu machen (unter Verwendung der Ideen aus Feathers 'Buch).
Péter Török
quelle
Ich würde dies +3, wenn ich könnte. WELC ist eine wesentliche Lektüre und auf jeden Fall für ein Refactoring gehen ...
Johnsyweb
Eine kleine Bemerkung zum zweiten Punkt ist, dass für Legacy-Systeme die Tests gemäß der Denkweise der Charakterisierungstests durchgeführt werden sollten . Das heißt, Sie können das aktuelle Verhalten der Software getreu erfassen und es unterlassen, das Verhalten zu ändern, auch wenn einige der Testergebnisse je nach Einstellung des Komponententests seltsam oder nicht akzeptabel erscheinen. (Übrigens stammt diese Idee auch vom Autor von WELC.)
rwong
@rwong, in der Tat. Ohne eine detaillierte Spezifikation oder einen sachkundigen Produktbesitzer kann der Entwickler nicht entscheiden, ob ein bestimmtes Verhalten des Programms a) beabsichtigt und erforderlich ist, b) unbeabsichtigt war, aber die Benutzer jetzt davon abhängen, c) einen Fehler, der Tatsächlich schadet es den Benutzern. d) Ein Fehler, der bisher völlig unbemerkt blieb. In den ersten beiden Fällen würde das "Korrigieren" den Benutzern tatsächlich schaden, und im letzten Fall würde das Korrigieren - obwohl theoretisch korrekt - keinen sichtbaren Nutzen bringen.
Péter Török
4

Die beste bekannte Methode ist die Mikado-Methode. http://mikadomethod.wordpress.com/2010/08/04/the-mikado-method-book/ Dies ist nur die Verallgemeinerung einer einfachen Technik, aber es ist die einzige Möglichkeit, die Codequalität in einer großen Codebasis zu verbessern ohne unnötige Risiken einzugehen.

WEWLC ist auch ein sehr gutes Buch darüber, aber in C ++ geschrieben zu sein ist mit Java- oder Ruby-Code nicht immer nützlich.

Uberto
quelle
2

Nachträgliche Anpassungstests an eine alte Codebasis können recht schwierig sein, wenn sie monolithisch aufgebaut ist.

Wenn möglich (haben Sie die Zeit / das Geld), wäre eine Möglichkeit, voranzukommen, den Code in testbarere Einheiten umzugestalten.

ozz
quelle
1

Ich möchte einen Link hinzufügen . Es gibt nur wenige Beispiele für nicht so einfach zu testende Implementierungen, die in mehr xUnit-freundlichem Code umgesetzt wurden. Als allgemeine Vorgehensweise versuchen Sie es mit den bereits erwähnten Links (Joel Post, Working With Legacy Code)

Yoosiba
quelle