it-swarm.com.de

Schreiben von Tests für vorhandenen Code

Angenommen, man hatte ein relativ großes Programm (z. B. 900.000 SLOC in C #), das alle gründlich kommentiert/dokumentiert wurde, gut organisiert ist und gut funktioniert. Die gesamte Codebasis wurde von einem einzelnen leitenden Entwickler geschrieben, der nicht mehr im Unternehmen tätig ist. Der gesamte Code ist so wie er ist testbar und IoC wird durchgehend verwendet - außer aus irgendeinem seltsamen Grund haben sie keine Komponententests geschrieben. Jetzt möchte Ihr Unternehmen den Code verzweigen und Unit-Tests hinzufügen, um festzustellen, wenn Änderungen die Kernfunktionalität beeinträchtigen.

  • Ist das Hinzufügen von Tests eine gute Idee?
  • Wenn ja, wie würde man überhaupt mit so etwas anfangen?

EDIT

OK, also hatte ich keine Antworten erwartet, die gute Argumente für entgegengesetzte Schlussfolgerungen liefern. Das Problem kann ohnehin nicht in meinen Händen liegen. Ich habe auch die "doppelten Fragen" durchgelesen und der allgemeine Konsens ist, dass "Tests schreiben gut ist" ... ja, aber in diesem speziellen Fall nicht allzu hilfreich.

Ich glaube nicht, dass ich hier alleine bin, wenn ich darüber nachdenke, Tests für ein Legacy-System zu schreiben. Ich werde Metriken darüber aufbewahren, wie viel Zeit aufgewendet wird und wie oft die neuen Tests Probleme erkennen (und wie oft sie dies nicht tun). Ich werde zurückkommen und dies in ungefähr einem Jahr mit meinen Ergebnissen aktualisieren.

SCHLUSSFOLGERUNG

Es stellt sich also heraus, dass es grundsätzlich unmöglich ist, dem vorhandenen Code einen Unit-Test mit einem Anschein von Orthodoxie hinzuzufügen. Sobald der Code funktioniert, können Sie Ihre Tests offensichtlich nicht mehr rot/grün beleuchten. In der Regel ist nicht klar, welche Verhaltensweisen zu testen sind, nicht klar, wo Sie beginnen sollen, und sicherlich nicht klar, wann Sie fertig sind. Selbst wenn man diese Frage stellt, geht es überhaupt nicht darum, Tests zu schreiben. In den meisten Fällen fand ich es tatsächlich einfacher, den Code mit TDD neu zu schreiben, als die beabsichtigten Funktionen zu entschlüsseln und in Unit-Tests rückwirkend hinzuzufügen. Wenn Sie ein Problem beheben oder eine neue Funktion hinzufügen, ist dies eine andere Geschichte, und ich glaube, dass dies die Zeit ist, Unit-Tests hinzuzufügen (wie einige unten ausgeführt haben). Schließlich wird der meiste Code neu geschrieben, oft früher als erwartet. Mit diesem Ansatz konnte ich einem überraschend großen Teil der vorhandenen Codebasis eine Testabdeckung hinzufügen.

70
Paul

Während Tests eine gute Idee sind, sollte der ursprüngliche Codierer sie erstellen, während er die Anwendung erstellt, um sein Wissen über den Code zu erfassen soll funktionieren und was kaputt gehen könnte, was dann auf dich übertragen worden wäre.

Bei diesem Ansatz besteht eine hohe Wahrscheinlichkeit, dass Sie die Tests schreiben, bei denen die Wahrscheinlichkeit am geringsten ist, dass sie brechen, und die meisten Edge-Fälle übersehen, die beim Erstellen der Anwendung entdeckt worden wären.

Das Problem ist, dass der größte Teil des Wertes aus diesen „Fallstricken“ und weniger offensichtlichen Situationen stammt. Ohne diese Tests verliert die Testsuite praktisch ihre gesamte Wirksamkeit. Darüber hinaus wird das Unternehmen ein falsches Sicherheitsgefühl in Bezug auf seine Anwendung haben, da es nicht wesentlich regressionssicherer ist.

Normalerweise besteht die Art und Weise, mit dieser Art von Codebasis umzugehen, darin, Tests für neuen Code und für das Refactoring von altem Code zu schreiben, bis die ältere Codebasis vollständig überarbeitet ist.

Auch siehe .

69
FMJaguar

Ja, das Hinzufügen von Tests ist definitiv eine gute Idee.

Sie sagen, dass es gut dokumentiert ist, und das bringt Sie in eine gute Position. Versuchen Sie, Tests anhand dieser Dokumentation als Leitfaden zu erstellen, wobei Sie sich auf Teile des Systems konzentrieren, die entweder kritisch sind oder häufigen Änderungen unterliegen.

Anfangs wird die schiere Größe der Codebasis im Vergleich zu der geringen Anzahl von Tests wahrscheinlich überwältigend erscheinen, aber es gibt keinen Big-Bang-Ansatz, und es ist wichtiger, einen Anfang zu machen irgendwo als sich zu quälen, was der beste Ansatz ist wird sein.

Ich würde Michael Feathers 'Buch Effektiv mit Legacy-Code arbeiten für einige gute, detaillierte Ratschläge empfehlen.

35
Danny Woods

Nicht alle Unit-Tests haben den gleichen Nutzen. Der Vorteil eines Komponententests liegt darin, dass er fehlschlägt. Je weniger wahrscheinlich es ist, dass es versagt, desto weniger vorteilhaft ist es. Neuer oder kürzlich geänderter Code enthält mit größerer Wahrscheinlichkeit Fehler als selten geänderter Code, der in der Produktion gut getestet wurde. Daher sind Unit-Tests mit neuem oder kürzlich geändertem Code mit größerer Wahrscheinlichkeit vorteilhafter.

Nicht alle Unit-Tests sind gleich teuer. Es ist viel einfacher, trivialen Code zu testen, den Sie heute selbst entworfen haben, als komplexen Code, den jemand anderes vor langer Zeit entworfen hat. Außerdem spart das Testen während der Entwicklung normalerweise Entwicklungszeit. Bei Legacy-Code sind diese Kosteneinsparungen nicht mehr verfügbar.

In einer idealen Welt hätten Sie alle Zeit, um Legacy-Code zu testen, aber in der realen Welt ist es naheliegend, dass die Kosten für das Hinzufügen von Unit-Tests zu Legacy-Code die Vorteile überwiegen. Der Trick besteht darin, diesen Punkt zu identifizieren. Ihre Versionskontrolle kann Ihnen helfen, indem sie Ihnen den zuletzt geänderten und am häufigsten geänderten Code anzeigt. Sie können diese zunächst einem Unit-Test unterziehen. Wenn Sie in Zukunft Änderungen vornehmen, testen Sie diese Änderungen und den eng verwandten Code auf Einheitentest.

Wenn Sie dieser Methode folgen, haben Sie schließlich eine ziemlich gute Abdeckung in den vorteilhaftesten Bereichen. Wenn Sie stattdessen Monate damit verbringen, Unit-Tests durchzuführen, bevor Sie die umsatzgenerierenden Aktivitäten wieder aufnehmen, ist dies möglicherweise eine wünschenswerte Entscheidung für die Softwarewartung, aber eine schlechte Geschäftsentscheidung.

21
Karl Bielefeldt

Ist das Hinzufügen von Tests eine gute Idee?

Absolut, obwohl ich es ein wenig schwer finde zu glauben, dass der Code sauber ist und gut funktioniert und moderne Techniken verwendet und einfach keine Komponententests hat. Sind Sie sicher, dass sie nicht in einer separaten Lösung sitzen?

Wenn Sie den Code erweitern/pflegen möchten, sind echte Komponententests für diesen Prozess von unschätzbarem Wert.

Wenn ja, wie würde man überhaupt mit so etwas anfangen?

Ein Schritt auf einmal. Wenn Sie mit Unit-Tests nicht vertraut sind, lernen Sie etwas. Wenn Sie mit den Konzepten vertraut sind, wählen Sie einen kleinen Abschnitt des Codes aus und schreiben Sie Tests dafür. Dann der nächste und der nächste. Die Codeabdeckung kann Ihnen dabei helfen, verpasste Stellen zu finden.

Es ist wahrscheinlich am besten, zuerst gefährliche/riskante/wichtige Dinge auszuwählen, um sie zu testen, aber Sie könnten effektiver sein, wenn Sie etwas direkt testen, um zuerst in einen Groove zu gelangen - insbesondere, wenn Sie/das Team nicht an die Codebasis und/oder Einheit gewöhnt sind testen.

9
Telastyn

Ja, Tests sind eine gute Idee. Sie helfen dabei, die vorhandene Codebasis wie beabsichtigt zu dokumentieren und unerwartetes Verhalten zu erkennen. Auch wenn die Tests anfänglich fehlschlagen, lassen Sie sie und überarbeiten Sie den Code später, damit sie bestanden werden und sich wie beabsichtigt verhalten.

Schreiben Sie Tests für kleinere Klassen (solche, die keine Abhängigkeiten haben und relativ einfach sind) und wechseln Sie zu größeren Klassen (solche, die Abhängigkeiten haben und komplexer sind). Es wird lange dauern, aber seien Sie geduldig und beharrlich, damit Sie die Codebasis schließlich so weit wie möglich abdecken können.

3
Bernard

OK, ich werde die gegenteilige Meinung abgeben ...

Das Hinzufügen von Tests zu einem vorhandenen, funktionierenden System wird dieses System ändern, es sei denn, das System ist von Anfang an mit Verspottung geschrieben. Ich bezweifle es, obwohl es durchaus möglich ist, dass alle Komponenten mit leicht definierbaren Grenzen, in die Sie Ihre Scheinschnittstellen einfügen können, gut voneinander getrennt sind. Wenn dies nicht der Fall ist, müssen Sie wichtige (relativ gesehen) Änderungen vornehmen, die möglicherweise zu Problemen führen. Im besten Fall werden Sie viel Zeit damit verbringen, diese Tests zu schreiben. Diese Zeit könnte besser genutzt werden, um stattdessen eine Menge detaillierter Konstruktionsdokumente, Auswirkungsanalyse-Dokumente oder Lösungskonfigurationsdokumente zu schreiben. Das ist schließlich die Arbeit, die Ihr Chef mehr als nur Unit-Tests machen möchte. Ist es nicht?

Auf jeden Fall würde ich keinerlei Unit-Tests hinzufügen.

Ich würde mich auf externe, automatisierte Testtools konzentrieren, die Ihnen eine angemessene Abdeckung bieten, ohne etwas zu ändern. Wenn Sie dann Änderungen vornehmen möchten, können Sie Unit-Tests innerhalb der Codebasis hinzufügen.

3
gbjbaanb

Ich bin oft auf diese Situation gestoßen, habe eine große Codebasis ohne ausreichende oder keine Testabdeckung geerbt und bin jetzt dafür verantwortlich, Funktionen hinzuzufügen, Fehler zu beheben usw.

Mein Rat ist, sicherzustellen und zu testen, was Sie hinzufügen. Wenn Sie Fehler beheben oder Anwendungsfälle im aktuellen Code ändern, testen Sie den Autor. Wenn Sie etwas anfassen müssen, schreiben Sie an dieser Stelle Tests.

Wenn dies zusammenbricht, ist der vorhandene Code für Unit-Tests nicht gut strukturiert, sodass Sie viel Zeit mit Refactoring verbringen, um Tests für geringfügige Änderungen hinzuzufügen.

2
Casey