Gibt es einen Wert beim Schreiben von Unit-Tests für Code, der bereits beim Erben von Anwendungen funktioniert?

27

Offensichtlich können einige alte Anwendungen nicht getestet werden oder sind aufgrund der Art und Weise, wie sie ursprünglich geschrieben wurden, extrem schwierig zu testen.

Aber sollte ich an bestimmten Stellen, wie bei einigen Hilfsmethoden, die wahrscheinlich Unit-Tests unterzogen werden könnten, Unit-Tests für sie schreiben?

Ich meine, sie könnten wie ein Hund geschrieben sein, aber so komplex die Logik auch sein mag, der Test der Zeit hat bewiesen, dass es so funktioniert, wie es sollte. Soll ich mich nur mit Unit-Tests beschäftigen, wenn ich sage, dass ich sie neu faktorisiere, oder soll ich Unit-Tests für sie schreiben, wenn ich Zeit habe?

Hat dies irgendeinen Wert?

Berücksichtigen Sie auch, dass die Methodendefinition vage sein kann und ich möglicherweise untersuchen muss, was einige der Methoden unter bestimmten Bedingungen tatsächlich tun sollten.

RoboShop
quelle
4
Tun Sie sich selbst einen Gefallen und lesen Sie Effektiv mit Legacy-Code arbeiten . Es ist ein ganzes Buch, das sich der Beantwortung dieser und anderer verwandter Fragen widmet.
Rein Henrichs

Antworten:

15

Ich denke, Sie sollten so viele Tests wie möglich für die Anwendung schreiben. Sie helfen Ihnen beim Erlernen der Codebasis und bereiten Sie auf die eventuelle Überarbeitung oder Neuentwicklung vor.

In diesem Szenario können einige Arten von Tests geschrieben werden, von denen jede ihre eigenen Vorzüge hat. Wenn Sie diese Tests schreiben, erfahren Sie viel über die Anwendung, mit der Sie sich befassen.

Schreiben Sie zunächst Tests, die das aktuelle Verhalten erfassen, ob es nun richtig oder falsch ist , bevor Sie mit dem Schreiben von Tests zur Überprüfung der Richtigkeit beginnen . Es ist eine ziemlich sichere Sache, dass Sie Fehler in Eckfällen oder in Teilen des Codes aufdecken werden, die durch Ausführen des Programms nicht gründlich getestet wurden. Machen Sie sich keine Gedanken darüber, was der Code tun soll, sondern erfassen Sie einfach, was er tut. Machen Sie sich im weiteren Verlauf keine Sorgen darüber, ob Sie den Code lesen oder ernsthafte Zeit damit verbringen, herauszufinden, wie die Ausgabe aussehen soll. Führen Sie einfach Ihren Test durch und erfassen Sie diese Ausgabe in einem Assert.

Dadurch erhalten Sie eine solide Grundlage für das Verständnis, wie der Code funktioniert und wo die Hauptschmerzpunkte oder Schwachstellen liegen können. Wenn Sie Fehler aufdecken, können Sie sich an Personen mit der Befugnis wenden, zu entscheiden, ob sie eine Korrektur wert sind oder nicht, und diese Entscheidungen treffen.

Als Nächstes können Sie einige größere (im Umfang) Tests schreiben, die Teile des Codes abdecken, die möglicherweise nicht einfach auf Einheiten getestet werden können, bei denen es aber dennoch wichtig wäre, die Workflows so weit wie möglich zu testen. Diese Workflow- oder Integrationstests bieten Ihnen, je nachdem, wie Sie sie anzeigen möchten, eine gute Grundlage für die Umgestaltung dieser Workflows, um sie testbarer zu machen und Sie zu schützen, wenn eine neue Funktion hinzugefügt werden muss, die sich möglicherweise auf einen vorhandenen Workflow auswirkt.

Im Laufe der Zeit werden Sie eine Reihe von Tests erstellen, die Ihnen oder der nächsten Person, die die Anwendung erbt, helfen sollen.

Adam Lear
quelle
13

Ich sehe Unit-Tests als Spezifikationen, nicht als bloße Tests. In dem von Ihnen genannten speziellen Fall wird der tatsächliche Wert ermittelt, wenn Sie einen Komponententest durchführen, bevor Sie Änderungen vornehmen, um die neuen Spezifikationen zu erfüllen. Wenn Sie den geerbten Code ändern möchten, ist es meiner Ansicht nach am besten, Einheitentests für die Funktionalität durchzuführen. Dies bringt nicht nur ein Sicherheitsnetz mit sich, sondern hilft uns auch, mehr Klarheit darüber zu schaffen, was diese bestimmte Einheit tut. Dies kann Sie auch zu Recherchen zwingen, wie von Ihnen erwähnt, was für das Verständnis von Nutzen ist. Ich gehe also davon aus, dass ein Modultest durchgeführt wird, bevor er geändert wird.

Vinod R
quelle
Schreiben Sie die Tests in der Sprache der höchsten Stufe, die funktionieren wird. Wenn Sie aufgefordert werden, die Zeit für eine Änderung zu schätzen, geben Sie die Zeit an, die zum Schreiben der fehlenden Tests erforderlich ist. Sie brauchen möglicherweise länger, um die Änderung vorzunehmen, aber Sie werden viel weniger Fehler in das Feld bringen.
Kevin Cline
8
 > Is there any value in writing unit tests for code that 
 > already works when inheriting applications?

NO . Nach meiner Erfahrung besteht ein schlechtes Kosten-Nutzen-Verhältnis für das Schreiben von Komponententests, nachdem der Produktionscode geschrieben wurde, da es ziemlich unwahrscheinlich / schwierig ist, Wege zu finden, um den Code ohne schweres Refactoring isoliert zu testen . Einer der Vorteile der testgetriebenen Entwicklung besteht darin, dass Sie lose gekoppelten Code erhalten. Wenn Sie die Tests danach schreiben, ist die Wahrscheinlichkeit hoch, dass der Code eng gekoppelt ist.

JA, Sie können Integrationstests für die Anwendung für die Funktionen schreiben, an denen Sie Änderungen vornehmen möchten. Auf diese Weise können Sie einen Regressionstest durchführen, um festzustellen, ob Ihre Änderungen zu Problemen führen.

JA aus Sicht der Qualität und des Entwicklers ist es wertvoll, Tests durchzuführen.

NEIN aus geschäftlicher Sicht, da es sehr schwierig ist, dem Kunden zu verkaufen, dass Sie Zeit / Geld benötigen, um keinen wirklichen Geschäftswert zu erzielen, aber das vage Versprechen, dass geschäftliche Änderungen die Dinge nicht verschlimmern werden.

k3b
quelle
+1 für Integrationstests anstelle von Komponententests für diesen Fall. Sehr pragmatische Ratschläge
gbjbaanb
5

Wenn überhaupt möglich, gibt es noch mehr Gründe, Tests für vorhandenen Code zu schreiben, der "bereits funktioniert". Wenn es keine Tests gibt, ist der Code wahrscheinlich geruchsintensiv und könnte einer umfassenden Überarbeitung unterzogen werden, um Verbesserungen zu erzielen. Die Testsuite hilft Ihnen bei der Umgestaltung. Es könnte sich sogar herausstellen, dass der ursprüngliche Code nicht richtig funktioniert. Ich erinnere mich, dass ich einmal einen Test für eine Methode geschrieben habe, mit der ein Verkaufsbericht erstellt wurde, und festgestellt habe, dass diese Methode die Dinge nicht richtig berechnet hat. Daher waren die Verkäufe einige tausend Dollar höher als sie tatsächlich waren (Zum Glück war es nicht das eigentliche finanzielle Ende der Dinge, sondern nur eine Schätzung des Verkaufsberichts).

Natürlich gilt dieser Rat nur , wenn Sie tatsächlich können die Tests schreiben. Nach meiner Erfahrung ist es fast unmöglich, eine Codebasis ohne Tests nachzurüsten, da Sie die Hälfte der Codemodule neu schreiben müssten, um abstrakt genug zu sein, um zuerst das Testen zu unterstützen, und Sie werden dies nicht tun können.

Wayne Molina
quelle
Warum eine Ablehnung für die Erklärung der Wahrheit?
Wayne Molina
4

Auf jeden Fall , denn Unit-Tests sollten nicht die Richtigkeit überprüfen, sondern das tatsächliche Verhalten des Systems charakterisieren. Insbesondere bei einem Legacy-Projekt sind viele der Anforderungen implizit im tatsächlichen Verhalten codiert.

Diese Charakterisierung dient als Basis für die Funktionalität. Auch wenn das Verhalten vom geschäftlichen Standpunkt aus falsch ist, können Sie eine weitere Verschlechterung des Verhaltens ausschließen. Es kann schwierig sein, in einem Legacy-Projekt Fuß zu fassen. Auf diese Weise erhalten Sie eine Ausgangsbasis, um voranzukommen, ohne die Situation zu verschlechtern.

Schreiben Sie also alle Komponententests, die Sie können. Bei Code, der nicht getestet werden kann, müssen Sie Ihren Code so umgestalten, dass Abhängigkeiten voneinander getrennt werden, indem Sie "Nähte" in den Code einfügen - Stellen, an denen Sie den Code, den Sie testen möchten, von dem Code trennen können, den Sie nicht testen möchten.

Die Ideen von Komponententests als Charakterisierungstests und Nähte sind die Hauptpunkte von Working Effectively with Legacy Code von Michael Feathers, ein Buch, das ich sehr empfehlen kann.

Matthew Rodatus
quelle
2

Ich habe selbst darüber nachgedacht, da es ziemlich viele undokumentierte, schweißtreibend schlecht geschriebene, aber in unserem System funktionierende Legacy-Codes gibt.

Sie machen einen guten Punkt:

Soll ich mich nur mit Unit-Tests beschäftigen, wenn ich sage, dass ich sie neu faktorisiere, oder soll ich Unit-Tests für sie schreiben, wenn ich Zeit habe?

Wenn sich die Anforderungen ändern, ist es meiner Meinung nach am wertvollsten, die Einheitentests zu schreiben. Wenn nicht, würde ich mich nicht besonders darum kümmern, da Sie nicht in der Lage wären, ordnungsgemäße Tests zu schreiben, da Sie nicht alle Bedingungen kennen.

wann immer ich die zeit habe

Sie haben Zeit, um Prioritäten zu setzen, oder? Also wird es sowieso nie passieren. :)

Michael
quelle
1

Versuchen Sie, Aspekte dieser Codebasis zu nutzen, die zuvor nicht in einer Produktionsanwendung verwendet wurden? Schreiben Sie zuerst Komponententests für diese Szenarien. Sie müssen in der Lage sein, Ihre Arbeit hier zu priorisieren, und ich denke, The Art of Unit Testing hatte diesbezüglich einige Ratschläge (insbesondere, wie man sich dem Testen von Legacy-Codebasen nähert).

Justin Simon
quelle
1

Gehen Sie nicht davon aus, dass alles funktioniert, nur weil die Anwendung ausgeführt wird. In der Regel zeigt der "Test der Zeit" nur, dass a) Sie den Rest der Fehler noch nicht gefunden haben oder b) die gefundenen Personen sie haben sie nicht gemeldet. (Oder vielleicht beides.) Und selbst der Code, der jetzt vermutlich funktioniert, funktioniert möglicherweise nicht mehr, wenn Sie das nächste Mal eine Änderung vornehmen müssen.

Unit-Tests geben Ihnen ein gewisses Maß an Sicherheit, dass bestimmte Funktionen intakt bleiben, und bieten Ihnen die Möglichkeit, dies in einer angemessenen Anzahl von Fällen zu demonstrieren. Das ist bedeutend wertvoller als "herumzustöbern und zu testen", selbst für eine einzelne Fehlerbehebung. (Das Herumstöbern entspricht eher der Integration oder dem Testen von Systemen. In diesem Sinne kann das manuelle Testen der App mehr als das Testen von Einheiten allein abdecken, aber das ist immer noch ineffiziente Zeit. Selbst eine Methode zur Automatisierung dieser Tests ist dies besser als sie manuell zu machen.)

Sie sollten auf jeden Fall Tests schreiben, wenn Sie den Code ändern, egal ob er repariert oder umgestaltet wird. Sie sollten Tests so gut wie möglich schreiben, wenn Sie beim nächsten Mal, wenn Sie einen Defekt beheben müssen (und es wird ein nächstes Mal geben), nur um Zeit zu sparen. In diesem Fall tun Sie dies jedoch Diese Zeit muss gegen die Erwartungen der Leute abgewogen werden, die behaupten, dass Software immer fehlerfrei ist und somit Zeit für zukünftige Wartungsarbeiten "verschwendet" wird. (Das bedeutet jedoch nicht, dass Sie die aktuellen Zeitpläne ignorieren sollten.) Wenn Sie dies tun, haben Sie zu einem bestimmten Zeitpunkt eine ausreichende Abdeckung, mit der Sie den Nutzen von Tests für ältere Anwendungen demonstrieren können Zeit für zukünftige Apps, die irgendwann Zeit für die produktive Entwicklung freisetzen sollten.

Dave DuPlantis
quelle
0

Aus meinem Lala-Land-Herzen werde ich ja sagen und nicht nur das, sondern es hacken, umgestalten und weiter testen, aber stellen Sie sicher, dass Sie in anderen wichtigen Projekten nicht zurückbleiben. Wenn Ihr Job als arbeitender Programmierer gefährdet ist oder ein Manager Ihnen befohlen hat, die Verantwortung zu übernehmen, dann ja. Wenn das Team oder das Unternehmen darunter leiden könnte, verhandeln Sie mit Ihrem Manager, um ihm mitzuteilen, dass Tests erforderlich sind, um das Unternehmen vor einer Katastrophe zu bewahren. Wenn er sagt, machen Sie sich keine Sorgen, dann sind Sie aus dem Häppchen (nicht unbedingt, Schuldzuweisung ist eine Management-Fähigkeit, also stellen Sie sicher, dass Sie aus dem Häppchen sind ... wirklich!)

Viel Glück!

Armando
quelle