Ist das Hinzufügen von Komponententests für bekannten Legacy-Code sinnvoll?

21
  • Ich spreche von Unit-Tests im TDD-Sinne. (Nicht automatisierte "Integration" oder wie Sie es nennen möchten Tests.)
  • Legacy-Code wie in: (C ++) Code ohne Tests. (siehe: Michael Feathers ' Effektiv mit Legacy-Code arbeiten )
  • Aber auch Legacy-Code wie in: Code, mit dem unser Team in den letzten 10-5 Jahren gearbeitet hat, sodass wir sehr oft eine gute Vorstellung davon haben, wo Dinge platziert werden müssen, um etwas zu ändern.
  • Wir haben Unit-Tests für einige Module eingerichtet (über Boost.Test) , die später erschienen sind oder sich als " normal " für Unit-Tests erwiesen haben (allgemeine app-spezifische Container, Zeichenfolgen, Netzwerkhelfer usw.).
  • Wir haben noch keine ordnungsgemäßen automatischen Abnahmetests.

Jetzt, vor kurzem, hatte ich das "Vergnügen", 3 neue benutzerbezogene Funktionen zu implementieren.

Ich brauchte jeweils 1-2 Stunden, um mich mit den zu ändernden Codeteilen vertraut zu machen, 1-2 Stunden, um den (kleinen) Code zu implementieren, den ich ändern musste, und weitere 1-2 Stunden, um sicherzustellen, dass die App funktioniert lief danach richtig und tat was es tun sollte.

Jetzt habe ich wirklich wenig Code hinzugefügt. (Ich denke, eine Methode und ein paar Anrufzeilen für jede Funktion.)

Factoring diesen Code aus (über eine der vorgeschlagenen Methoden in WEwLC ), so dass ein Unit - Test sinnvoll haben würde (und nicht um eine vollständige Tautologie gewesen) wäre leicht weiteren 2-4 Stunden in Anspruch genommen, wenn nicht mehr. Dies hätte zu jeder Funktion 50% -100% mehr Zeit ohne unmittelbaren Nutzen beigetragen

  1. Ich brauchte den Unit-Test nicht, um etwas über den Code zu verstehen
  2. Manuelles Testen ist derselbe Arbeitsaufwand, da ich noch testen muss, ob der Code richtig in den Rest der App integriert ist.

Zugegeben, wenn später "jemand" kam und diesen Code berührte, könnte er theoretisch einen gewissen Nutzen aus diesem Komponententest ziehen. (Nur theoretisch, da diese getestete Codeinsel in einem Ozean von ungetestetem Code leben würde.)

"Dieses Mal" habe ich mich also entschieden, die harte Arbeit des Hinzufügens eines Komponententests nicht zu übernehmen: Die Codeänderungen, um das zu testende Material zu erhalten, wären erheblich komplexer gewesen als die Codeänderungen, um die Funktion korrekt (und sauber) zu implementieren.

Ist dies typisch für stark gekoppelten Legacy-Code? Bin ich faul / setzen wir als Team die falschen Prioritäten? Oder bin ich umsichtig und teste nur Dinge, bei denen der Overhead nicht zu hoch ist?

Martin Ba
quelle
Was ist, wenn eine andere Abteilung Ihren "bekannten Legacy-Code" übernimmt? Was werden die Jungs dort damit machen?
Alex Theodoridis

Antworten:

18

In diesen Situationen muss man pragmatisch sein. Alles muss einen geschäftlichen Wert haben, aber das Unternehmen muss darauf vertrauen, dass Sie beurteilen, welchen Wert technische Arbeit hat. Ja, Unit-Tests haben immer einen Vorteil, aber ist dieser Vorteil groß genug, um die aufgewendete Zeit zu rechtfertigen?

Ich würde immer über neuen Code streiten, aber bei Legacy-Code muss man ein Urteil fällen.

Bist du oft in diesem Bereich des Codes? Dann gibt es Gründe für eine kontinuierliche Verbesserung. Nehmen Sie eine wesentliche Änderung vor? Dann gibt es einen Fall, dass es sich bereits um neuen Code handelt. Aber wenn Sie einen einzeiligen Code in einem komplexen Bereich erstellen, der wahrscheinlich ein Jahr lang nicht mehr angesprochen wird, sind die Kosten (ganz zu schweigen vom Risiko) für die Neuentwicklung natürlich zu hoch. Geben Sie einfach eine Codezeile ein und gehen Sie schnell duschen.

Faustregel: Denken Sie immer an sich selbst: " Glaube ich, dass das Unternehmen mehr von dieser technischen Arbeit profitiert, von der ich denke, dass ich sie tun sollte, als von der Arbeit, nach der sie gefragt haben, die sich infolgedessen verzögert? "

pdr
quelle
Was ist ein guter Code? Eine, die gut entworfen, getestet, dokumentiert und zukunftssicher ist oder für die Sie bezahlt werden? Wie immer: Sie können es gut haben ; du kannst es billig haben ; Sie können es schnell haben . Wählen Sie zwei, der dritte ist Ihre Kosten.
Sardathrion - Wiedereinsetzung von Monica 24.10.11
2
"Ich würde immer über neuen Code streiten" ... "neuen Code" in einer alten Codebasis oder "neuen neuen Code"? :-)
Martin Ba
pdr hat die richtige idee. Es ist eine technische Entscheidung (eine mit Kompromissen). Wenn Sie einen großen Teil des geprüften Codes haben, ist es im Allgemeinen eine gute Idee, ihn in Ruhe zu lassen. Ich habe gesehen, wie TDD-Bemühungen um Legacy-Code (nur ein Jahr, aber das reicht) Monate gekostet haben und nur Monate damit verbracht haben, Geld auszugeben und eine Legacy-App zu brechen, bis die vom TDD-Refactor eingeführten Fehler behoben waren. Wenn der Code / die Funktion fertig ist und getestet wurde, brechen Sie ihn / sie nicht, um Instrumentation (TDD) hinzuzufügen, um Ihnen etwas mitzuteilen, das Sie ohnehin schon gewusst haben (dass es funktioniert).
Anon
10

Der Vorteil von Unit-Tests im Sinne von TDD besteht darin, etwas zu erhalten, das für sich steht, ohne dass eine über Jahre hinweg von einem stabilen Team aufgebaute mündliche Überlieferung erforderlich ist.

Es ist ein großes Glück, dass dasselbe Team schon so lange an einem Projekt beteiligt ist. Aber das wird sich irgendwann ändern. Menschen werden krank, gelangweilt oder befördert. Sie ziehen um, ziehen sich zurück oder sterben. Neue kommen mit neuen Ideen und dem Drang, alles so umzugestalten, wie sie es in der Schule gelernt haben. Unternehmen werden verkauft und gekauft. Verwaltungsrichtlinien ändern sich.

Wenn Sie möchten, dass Ihr Projekt überlebt, müssen Sie es auf Änderungen vorbereiten.

mouviciel
quelle
3

Das Schreiben von Komponententests ist eine Zukunftssicherung Ihres Codes. Wenn die Codebasis keine Tests enthält, sollten Sie neue Tests für alle neuen Funktionen hinzufügen, da dies den Code nur ein wenig robuster macht.

Ich finde, dass das Hinzufügen von Tests, selbst in Legacy-Code, mittel- bis langfristig vorteilhaft ist. Wenn es Ihrem Unternehmen mittel- bis langfristig egal ist, würde ich ein anderes Unternehmen suchen. Außerdem glaube ich nicht, dass das manuelle Testen länger dauert als das Schreiben eines festgelegten Komponententests. In diesem Fall müssen Sie Code-Kata üben, die sich auf das Schreiben von Tests konzentriert.

Sardathrion - Setzen Sie Monica wieder ein
quelle
1
Aber, aber, aber! :-) Das sollte zu einer Zeitersparnis von 100% führen, die für die Implementierung einer neuen Funktion benötigt wird. Die für die Implementierung nachfolgender Funktionen erforderliche Zeit wird dadurch nicht verkürzt. Dies kann die Zeit verkürzen, die zum Wechseln des Materials benötigt wird.
Martin Ba
3
Sie stellen sicher, dass Änderungen in diesem Bereich des Codes keine neuen Fehler hervorrufen, dass neue (weniger erfahrene) Benutzer den Code besser verstehen und dass Nebenwirkungen, die diesen Bereich betreffen, beim Testen und nicht bei der Veröffentlichung auftreten Zeit. Das Testen hilft zu überprüfen, ob der Code das tut, was er sollte, und erleichtert das spätere Hinzufügen von Features nicht. Ich finde, dass das Hinzufügen von Tests, selbst in Legacy-Code, mittel- bis langfristig vorteilhaft ist . Wenn es Ihrem Unternehmen mittel- bis langfristig egal ist, würde ich ein anderes Unternehmen suchen.
Sardathrion - Wiedereinsetzung von Monica
1
@Martin, weil klar ist, was Sie tun, Code, was Sie denken, die Funktion sein sollte, und versenden Sie es dann. Es werden zu keinem Zeitpunkt Tests durchgeführt ... nein, warten Sie. Als Entwickler testen wir alle unseren Code (zumindest von Hand), bevor wir sagen, dass er fertig ist. Das Ersetzen von "von Hand" durch "durch Schreiben eines automatisierten Tests" bedeutet keine 100% ige Zeitsteigerung. Häufig finde ich, dass es ungefähr zur gleichen Zeit gedauert hat.
Kaz Dragon
1
@Kaz - "Ersetzen" von Hand durch "durch Schreiben eines automatisierten Tests" ist keine 100% ige Zeitsteigerung. Ich finde, es wird ungefähr dieselbe Zeit benötigt. " - YMMV, aber für meine Codebasis ist dies eindeutig falsch (wie in der Frage dargelegt).
Martin Ba
3
@Kaz: Was ich meinte :-) war: Ein Unit Test testet meinen Code isoliert. Wenn ich keinen Komponententest schreibe, teste ich den Code nicht isoliert, sondern nur, wenn der Code korrekt aufgerufen wird und das gewünschte Ergebnis in der App erzeugt. Diese beiden Punkte (richtig genannt und App-macht-was-es-soll) muss ich auf jeden Fall (manuell) testen und werden von einem Unit-Test nicht abgedeckt. Und der Unit-Test würde diese beiden Punkte nicht abdecken, sondern "nur" meine Funktion für sich testen. (Und dieser Unit-Test-Test wäre zusätzlich und würde, soweit ich sehen kann, durch nichts ausgeglichen.)
Martin Ba
2

Best Practices schreiben vor, dass Sie jeden Code, den Sie ändern, einem Komponententest unterziehen sollten. Die Codierung in der realen Welt ist jedoch mit vielen Kompromissen verbunden, da Zeit und Material begrenzt sind.

Sie müssen lediglich die tatsächlichen Kosten für das Beheben von Fehlern und das Vornehmen von Änderungen ohne Komponententests bewerten. Sie können dann die Investition in die Erstellung dieser Tests bewerten. Unit-Tests reduzieren die Kosten für zukünftige Arbeiten erheblich, haben aber jetzt ihren Preis.

Unterm Strich lohnt es sich möglicherweise nicht, Unit-Tests zu schreiben, wenn Ihr System selten geändert wird. Wenn es jedoch regelmäßigen Änderungen unterliegt, lohnt es sich.

Tom Squires
quelle
1

All diese kleinen rationalen Entscheidungen, keine Tests zu erstellen, führen zu einer lähmenden technischen Verschuldung, die Sie verfolgen wird, wenn jemand abreist und ein neuer Mitarbeiter eingestellt werden muss.

Ja, das Schreiben der Einheitentests hat möglicherweise weitere 2-3 Stunden gekostet. Wenn der Code jedoch vom Testen zurückgesendet wird, müssen Sie alles manuell erneut testen und Ihre Tests erneut dokumentieren - tun Sie das, nicht wahr? Woher weiß sonst jemand, was Sie getestet haben und welche Werte Sie verwendet haben?

Unit-Tests dokumentieren das erwartete Verhalten des Codes, die Testdaten, die zur Überprüfung der Funktionalität verwendet wurden, und geben neuen Codierern die Gewissheit, dass sie beim Vornehmen von Änderungen nichts kaputt gemacht haben.

Es kostet heute ein paar Stunden mehr als manuelles Testen, aber Sie testen jedes Mal, wenn Sie Änderungen vornehmen, um Stunden über die Lebensdauer des Codes zu sparen.

Wenn Sie jedoch wissen, dass der Code in ein paar Jahren in den Ruhestand geht, haben sich alle von mir genannten Änderungen geändert, da Sie die Tests im Code nicht abgeschlossen haben und es sich nie auszahlt.

mcottle
quelle
"Und dokumentieren Sie noch einmal Ihre Tests - tun Sie das, nicht wahr?" - {zynischen Hut aufsetzen:} Natürlich nicht. Wir sind nicht im Entwickler-Märchenland. Sachen werden implementiert und getestet und ausgeliefert. Später wird es kaputt und repariert und getestet und ausgeliefert.
Martin Ba
Ich würde hoffen, dass alles unabhängig von der Anzahl der Unit-Tests manuell getestet wird. Automatisierte Abnahmetests sind eine ganz andere Sache. Akzeptanztests werden jedoch nicht dadurch erschwert, dass es sich bei der Codebasis um ein Vermächtnis handelt.
pdr
2
mcottle - Ihnen fehlt ein wichtiger Punkt. Das Testen der Einheit verringert nicht die Zeit, die für das "manuelle Testen der Funktionalität" der fertigen Funktion benötigt wird. Ich muss mich noch durch alle Dialoge klicken, die mit einer vorsichtigen Untergruppe möglicher Eingaben zu tun haben, um sicherzustellen, dass die tatsächlich fertiggestellte App das tut, was sie tun soll. (Ich gebe zu, dass theoretische Komponententests dazu beitragen können, diesen manuellen Testzyklus auf nur eine Schleife zu beschränken, wenn die Komponententests sicherstellen, dass ich nur während des manuellen Tests keine offensichtlichen Probleme finde.)
Martin Ba
0

Der Wert von Komponententests besteht nicht nur darin, ein neues Feature zu testen, wenn es entwickelt wird. Der Nutzen von Unit-Tests wird größtenteils in der Zukunft erzielt.

Ja, Sie müssen möglicherweise ausgeben , was scheint wie eine ungeregelte Menge Zeit , um Ihren Legacy - Code testbar zu machen.

Wenn Sie dies nicht tun, werden oder sollten Sie noch viele, viele, viele Stunden damit verbringen, die Funktion zu testen. Nicht nur bei der ersten Entwicklung, sondern bei jeder neuen Version Ihrer Software. Ohne Sie und andere Formen des automatisierten Testens haben Sie keine andere Möglichkeit, als viele Stunden manuell zu testen, um sicherzustellen, dass Ihre Funktion nicht versehentlich beschädigt wurde, selbst wenn diese Funktion selbst nicht geändert wurde.

Marjan Venema
quelle
1
"Ohne Unit-Tests haben Sie keine anderen Mittel, um sicherzustellen, dass Ihr Feature nicht versehentlich beschädigt wurde, auch wenn dieses Feature selbst nicht geändert wurde." - Unit-Tests helfen nicht. Um wirklich sicherzugehen , müsste ich automatisierte Integrations- / Akzeptanztests durchführen.
Martin Ba
Ja, Unit-Tests sind nur der erste Schritt. Bearbeitete Antwort zur Klarstellung
Marjan Venema