Hat die testgetriebene Entwicklung (TDD) tatsächlich einem realen Projekt geholfen?


36

Ich bin nicht neu in der Codierung. Ich habe seit über 15 Jahren (ernsthaft) codiert. Ich hatte immer einige Tests für meinen Code. In den letzten Monaten habe ich jedoch testgetriebenes Design / Entwicklung (TDD) mit Ruby on Rails gelernt . Bisher sehe ich keinen Nutzen.

Ich sehe einen gewissen Vorteil darin, Tests für einige Dinge zu schreiben, aber nur für sehr wenige. Und obwohl mir die Idee gefällt, den Test zuerst zu schreiben, verbringe ich wesentlich mehr Zeit damit, meine Tests zu debuggen, damit sie sagen, was ich wirklich meine, als tatsächlichen Code zu debuggen. Dies liegt wahrscheinlich daran, dass der Testcode oft wesentlich komplizierter ist als der Code, den er testet. Ich hoffe, dies ist nur Unerfahrenheit mit den verfügbaren Tools ( RSpec in diesem Fall).

Ich muss jedoch sagen, dass das Maß an Frustration, das mit dem enttäuschenden Leistungsmangel einhergeht, derzeit unannehmbar ist. Bisher ist der einzige Wert, den ich von TDD sehe, eine wachsende Bibliothek von RSpec-Dateien, die als Vorlagen für andere Projekte / Dateien dienen. Das ist nicht viel nützlicher, vielleicht auch weniger nützlich als die eigentlichen Projektcode-Dateien.

Beim Lesen der verfügbaren Literatur stelle ich fest, dass TDD eine enorme Zeitverschwendung zu sein scheint, sich aber am Ende auszahlt. Ich frage mich nur, gibt es Beispiele aus der realen Welt? Zahlt sich diese massive Frustration in der realen Welt jemals aus?

Ich hoffe wirklich, dass ich diese Frage hier nicht verpasst habe. Ich habe gesucht, aber alle Fragen / Antworten sind zu diesem Zeitpunkt mehrere Jahre alt. Es war eine seltene Gelegenheit, als ich einen Entwickler fand, der etwas Schlechtes über TDD sagte, weshalb ich so viel Zeit damit verbracht habe wie ich. Mir ist jedoch aufgefallen, dass niemand auf konkrete Beispiele aus der Praxis zu verweisen scheint. Ich habe eine Antwort gelesen, die besagte, dass der Typ, der 2011 den Code debuggt, sich bei Ihnen für eine vollständige Unit-Testsuite bedanken würde (ich glaube, dieser Kommentar wurde 2008 abgegeben).

Ich frage mich nur, ob wir nach all den Jahren endlich Beispiele haben, die belegen, dass die Auszahlung echt ist. Hat jemand tatsächlich Code geerbt oder ist er auf Code zurückgekehrt, der mit TDD entwickelt wurde, über eine vollständige Reihe von Komponententests verfügt und sich tatsächlich ausgezahlt hat? Oder haben Sie festgestellt, dass Sie so viel Zeit damit verbracht haben, herauszufinden, was der Test testete (und warum es wichtig war), dass Sie einfach das ganze Durcheinander weggeworfen und sich in den Code eingegraben haben?


1
Es hat mir mehr Zeit gespart: weil wir viele Leute im selben Projekt sind, weil Juwelen-Updates einige unbekannte Nebenwirkungen haben können, weil wenn alles grün ist und ich einen Fehler habe, ich weiß, wo es nicht wert ist, seine Wurzel zu finden.
Uhr


3
butunclebob.com/ArticleS.UncleBob.JustTenMinutesWithoutAtest Hier ist eine Geschichte von Onkel Bob über eine reale Situation, mit der er konfrontiert war.
Hakan Deryal

1
Zuerst dachte ich, Tests wären großartig, um zu wissen, wo keine Bugs sind, aber ich lernte schnell, wie @Hakan im Artikel von Onkel Bob betonte, im Allgemeinen, weil Sie einen Testfall verpasst haben. Das macht diese Tests ziemlich nutzlos. In diesem Artikel wird darauf hingewiesen, dass inkrementelle Entwicklung funktioniert.
James

1
"Ich verbringe wesentlich mehr Zeit damit, meine Tests zu debuggen, damit sie sagen, was ich wirklich meine, als tatsächlichen Code zu debuggen." Aber ist das nicht genau der Vorteil? Verbringen Sie danach immer noch viel Zeit mit dem Debuggen des "tatsächlichen Codes"? Befürworter von TDD argumentieren, dass die Zeit, die aufgewendet wird, um einen Weg zu finden, Ihren Code testbar zu machen, tatsächlich ein Entwicklungsaufwand ist , der Ihrem Code zugute kommt.
Andres F.

Antworten:


26

Dieses Papier zeigt, dass TDD die Entwicklungszeit um 15-35% verlängert und die Defektdichte bei vergleichbaren Projekten um 40-90% verringert.

Der Artikel bezieht sich auf das vollständige Papier (pdf) - Nachiappan Nagappan, E. Michael Maximilien, Thirumalesh Bhat und Laurie Williams. „Qualitätsverbesserung durch testgetriebene Entwicklung: Ergebnisse und Erfahrungen von vier Industrieteams“. ESE 2008 .

AbstraktTestgetriebene Entwicklung (TDD) ist eine Softwareentwicklungspraxis, die seit Jahrzehnten sporadisch angewendet wird. Bei dieser Praxis wechselt ein Softwareentwickler von Minute zu Minute zwischen dem Schreiben fehlgeschlagener Komponententests und dem Schreiben von Implementierungscode, um diese Tests zu bestehen. Die testgetriebene Entwicklung hat sich vor kurzem als kritisches Kriterium für die Anwendung agiler Softwareentwicklungsmethoden herausgestellt. Es gibt jedoch nur wenige empirische Beweise, die den Nutzen dieser Praxis im industriellen Kontext belegen oder widerlegen. Es wurden Fallstudien mit drei Entwicklerteams bei Microsoft und einem bei IBM durchgeführt, die TDD übernommen haben. Die Ergebnisse der Fallstudien zeigen, dass die Fehlerdichte vor der Freigabe der vier Produkte im Vergleich zu ähnlichen Projekten, bei denen die TDD-Praxis nicht angewendet wurde, zwischen 40% und 90% abnahm. Subjektiv,

Das vollständige Papier fasst auch die relevanten empirischen Studien zu TDD und deren hochrangigen Ergebnissen kurz zusammen (Abschnitt 3 Verwandte Arbeiten ), darunter George und Williams 2003, Müller und Hagner (2002), Erdogmus et al. (2005), Müller und Tichy (2001), Janzen und Seiedian (2006).


2
Können Sie in einer Diskussion zu Meta.StackOverflow zusätzliche Informationen aus dem Artikel hinzufügen, die für den Fragesteller sowie für zukünftige Personen, die diese Frage finden, relevant sein könnten?
Thomas Owens

2
@ThomasOwens, ich dachte, die Schlussfolgerung ("TDD verlängert die Entwicklungszeit um 15-35% im Gegenzug für eine Verringerung der Defektdichte um 40-90%") war die zusätzliche Information, die die ursprüngliche Frage <_ <

4
Dieser Beitrag wurde markiert, weil er nicht genügend Informationen enthält. Ich habe die Zeitung noch nicht gelesen, aber es scheint, dass die Leute mehr Informationen wünschen, die zum Hauptteil der Antwort hinzugefügt werden. Besprechen Sie vielleicht mehr über die in der Studie verwendeten spezifischen Bedingungen?
Thomas Owens

99% aller Statistiken sind fiktiv. : P Aber eigentlich geht es um den Kontext. In was für einem Team? Eine große Herde mittelmäßiger Java-Entwickler? Ja, ich glaube, TDD würde ihnen bei der Produktivität helfen. Das heißt aber nicht, dass ihnen die architektonischen Fähigkeiten, robusten Code zu entwerfen und wertzuschätzen, in erster Linie nicht weiterhelfen würden, und IMO, Test-First TDD könnte sie sehr leicht daran hindern, jemals zu lernen, wie man das richtig macht. Und ja, ich habe gehört, dass es beim Design hilft. Bis zu einem gewissen Grad ist es wahrscheinlich wahr, aber es ist immer noch nicht zu erkennen und ein Pflaster für das Grundproblem IMO.
Erik Reppen

Es wäre schön, wenn noch weitere Artikel aus der ACM Digital Library aufgelistet würden oder die Stichwörter für die dortige Suchmaschine hinzugefügt würden. Wir brauchen mehr Genauigkeit in unseren Antworten, wenn wir über Agile und TDD sprechen
Rudolf Olah,

16

Ich sehe einen gewissen Vorteil darin, Tests für einige Dinge zu schreiben, aber nur für sehr wenige. Und obwohl mir die Idee gefällt, den Test zuerst zu schreiben, verbringe ich wesentlich mehr Zeit damit, meine Tests zu debuggen, damit sie sagen, was ich wirklich meine, als tatsächlichen Code zu debuggen.

Ich arbeite seit drei Jahren bei TDD und meine Erfahrung ist genau das Gegenteil. Ich verbringe weniger Zeit damit, Komponententests zu schreiben, bei denen ich den Code debuggen müsste, wenn ich die Komponententests nicht geschrieben hätte.

Ich mache nicht nur TDD, sondern arbeite auch von außen nach innen, dh ich implementiere zuerst TDD auf der obersten Ebene / GUI-Ebene. Durch die Implementierung der obersten Ebene werden die Anforderungen für die nächste Ebene im System definiert, die ich mit TDD usw. entwickle, bis der gesamte für das Feature erforderliche Code implementiert wurde. Oft stelle ich fest, dass nach der Implementierung einer Funktion wie dieser und dem Rauchentest der Funktion im eigentlichen System diese Funktion zum ersten Mal funktioniert. Nicht die ganze Zeit, aber oft.

Und da es viel länger dauert, ein Feature im eigentlichen System zu rauchen, als ein paar Unit-Tests durchzuführen, spare ich enorm viel Zeit. Tatsächlich ist es für mich schneller, eine Funktion mithilfe von TDD zu implementieren, als die Funktion zu implementieren, die überhaupt keine Komponententests schreibt.

Unit Tests zu schreiben ist jedoch eine Fähigkeit, die wie jede andere Programmierfähigkeit erlernt und gemeistert werden muss. Als ich mit TDD anfing, hatte ich 12 Jahre Berufserfahrung im Programmieren und war ein sehr versierter Programmierer. Ich dachte, dass das Schreiben großer Testsuiten für den Systemcode eine einfache Sache wäre. Aber als die Menge an Testcode zunahm und verschiedene Teile des Systems geändert wurden und vorhandene Tests modifiziert werden mussten, lernte ich, dass das Strukturieren und Schreiben von Komponententests an sich eine Fähigkeit ist, die gelernt und gemeistert werden muss. Auch ist nicht jeder Code gleichermaßen testbar. Der Systemcode muss sehr locker gekoppelt sein, um effizient testbar zu sein. Das Erlernen von TDD hat mir geholfen, den Systemcode lockerer zu koppeln.

Meine derzeitige Effizienz bei der Arbeit mit TDD beruht jedoch auf einer Kombination aus der Beherrschung des Schreibens von Komponententests und der Beherrschung der Technologie, in der das System implementiert ist (in diesem Fall C #).

TDD zu machen, während ich eine neue Technologie lerne, kann schwierig sein. Obwohl ich zum Beispiel ein bisschen iPhone-Programmierung gemacht habe, schreibe ich keine nennenswerte Anzahl von Komponententests, da ich weder die Sprache noch das Ziel c beherrsche oder beherrsche die Bibliothek. Daher habe ich keine Ahnung, wie ich meine Komponententests strukturieren soll, und noch weniger, wie ich den Systemcode strukturiere, um ihn testbar zu machen.

Aber wie gut funktioniert das bei echten Projekten?

An dem Projekt, an dem ich in den letzten Jahren gearbeitet habe, muss der Code zwar durch Komponententests ausreichend abgedeckt sein, aber ich bin der einzige im Team, der die ersten Tests schreibt. Die große Testsuite gibt mir jedoch das Vertrauen, das System umgestalten zu können, und ich bin davon überzeugt, dass das System ordnungsgemäß funktioniert, wenn die Testsuite erfolgreich ist.

Da jedoch viele Tests nach dem Systemcode geschrieben wurden, sind einige selbst fehlerhaft, dh sie testen nicht wirklich, was sie testen sollten. Dieses Imho kann nicht vermieden werden. Jedes Mal, wenn Sie einen Code schreiben, funktioniert der Code möglicherweise nicht wie beabsichtigt, dh es liegt ein Fehler vor. Gleiches gilt für Testcode. Daher besteht die Wahrscheinlichkeit, dass Sie einen Test schreiben, der erfolgreich ist, obwohl der zu testende Code nicht wie beabsichtigt funktioniert.

Wenn Sie den Test zuerst schreiben und nicht nur überprüfen, ob ein Testfehler vorliegt, sondern auch, ob der Test mit genau der Fehlermeldung fehlschlägt, die Sie vor der Implementierung des Systemcodes erwarten, wird das Risiko eines Fehlers im Komponententestcode erheblich verringert.

Zusammenfassend lässt sich sagen, dass Sie nach meiner Erfahrung, wenn Sie die Kunst des TDD beherrschen, nicht nur auf lange Sicht Zeit sparen, sondern auch im Voraus Zeit sparen werden. Aber es braucht Zeit, auch für einen erfahrenen Programmierer, um die Kunst des TDD zu beherrschen. Und es dauert noch länger, bis ein Team von Entwicklern mit unterschiedlichen Fähigkeiten die Kunst des TDD beherrscht.


9

Wir haben massiv profitiert.

Wir sind Tier-1-Händler, was bedeutet, dass wir mehr als sechs Millionen Zahlungsvorgänge pro Jahr abwickeln.

Unser Zahlungsgateway-System verfügt über Tausende von Unit- und Integrationstests. Diese Tests geben uns Vertrauen in unsere Fähigkeit, Zahlungen zu verarbeiten. Sie möchten sicher sein, dass Ihre Fahrzeugbremsen funktionieren, nicht wahr? Wir möchten sicher sein, dass wir unser Geschäft nicht verlieren, weil wir keine Zahlungen verarbeiten können.

Codeabdeckung gibt Ihnen dieses Vertrauen. Natürlich ist es nicht genug für sich, aber es ist ein sehr guter Anfang.

Der Großteil unseres Zahlungsgateway-Systems wurde mit TDD geschrieben. Einige Aspekte waren ziemlich schwierig zu testen, daher haben wir uns entschlossen, durch Einbußen bei der Codeabdeckung Abstriche zu machen. Wir werden uns umgehend mit diesen Problemen befassen.

Persönlich finde ich es schwierig, eine Logik zu schreiben, bevor ich Tests schreibe. Trotzdem dauerte es eine Weile, bis ich anfing, nach TDD-Art zu denken.

Visa PCI-Referenz: http://usa.visa.com/merchants/risk_management/cisp_merchants.html


3
"Wir werden uns irgendwann mit diesen Problemen befassen." - wahrscheinlich nicht ... nicht, wenn sie dich nicht mit einem schrecklichen Käfer schlagen. Diese Bereiche werden das Rückgrat für alles andere sein und werden das gesamte Design vorantreiben, da niemand die Ressourcen investieren möchte, um sie zu wiederholen, und niemand Änderungen erzwingen möchte, die möglicherweise etwas Schlechtes bewirken. Passiert jedes Mal: ​​P
Edward Strange

Sie raten, wenn ich Ihnen erzähle, was im Unternehmen passiert. Wenn wir ein Commit durchführen, können wir Code mit einer Codeabdeckung von 70% festschreiben. Dies wird durch CI-Blei ständig erhöht. Innerhalb weniger Monate wird der Mindestschwellenwert für die Codeabdeckung um einen kleinen Prozentsatz erhöht. Danach bleibt keine andere Wahl, als weitere Tests einzuführen.
CodeART

7

Obwohl Tests von manchen Leuten oft nur als eine Möglichkeit angesehen werden, zu viel zu tun, denke ich, dass es sich in bestimmten Fällen wirklich lohnt, sich die Mühe zu machen.

Ich habe seit ungefähr 3 Monaten einen Killer Sudoku Solver für die Schule entwickelt. Er verwendet viele "Strategien", um Möglichkeiten und Lösungen zu entfernen. Tatsache ist, dass ein Fehler in einer Möglichkeit schwerwiegend sein kann und zu einem Problem beim Lösen des Sudoku führen kann, da Sie es nicht mehr versuchen, wenn eine Möglichkeit beseitigt ist, und das Programm es nicht lösen kann, wenn es die Lösung war das Gitter mehr.

Aber es ist wirklich schwer, manuell zu testen, ich meine, es gibt ein Raster, ich kann sehen, welche Strategien was in einem realen Beispiel tun, aber ich kann nicht jedes Mal überprüfen, wann eine Strategie angewendet wird, weil dies zu viele Daten darstellt.

Und Strategien, die auf ein bestimmtes Raster angewendet werden, sind ziemlich "zufällig", das heißt, Sie werden nicht alle auf ein bestimmtes Raster anwenden.

Also schrieb ich Tests zu jeder Strategie, überprüfte das Ergebnis für jede Zelle und benutzte dabei nur einfache Situationen (zum Beispiel haben nur zwei Zellen bereits Möglichkeiten beseitigt). Das ersparte mir Stunden an einem Tag, an dem ich leider ein Gitter hatte, das nicht gelöst werden konnte. Weil ich schon wusste, wo das Problem liegt.


2
Ich habe das Gefühl, dass diese Frage beim Test zuerst mehr aufwirbelt und später stratergy implementiert. Tests eignen sich natürlich zum Debuggen von Anwendungen, bei denen es mühsam wäre, alle Möglichkeiten selbst zu testen.
Alex Hope O'Connor

6

Der Vorteil von TDD ist, dass Sie herausfinden, wie Sie Ihren Code aufrufen , bevor Sie den eigentlichen Code schreiben.

Mit anderen Worten, TDD hilft beim Entwerfen Ihrer API.

Nach meiner Erfahrung führt dies zu besseren APIs, die wiederum besseren Code liefern.


EDIT: Wie ich schrieb, war dies "in meiner Erfahrung", dh beim Schreiben von "Projekten in der realen Welt", aber leider ist dies mit einer geschlossenen Quellcodebasis, die ich der Welt nicht zeigen kann. Ich kann den Kommentaren entnehmen, dass dies tatsächlich verlangt wird und nicht nur eine Bestätigung der bloßen Existenz solcher Projekte.

Ich habe auch - wieder in meiner persönlichen Erfahrung - festgestellt, dass sich der wahre Nutzen zeigt, wenn Sie in den Wartungsmodus wechseln, weil sich die Anforderungen ändern. Die saubereren APIs haben es viel einfacher gemacht, die neuen oder geänderten Anforderungen im Testcode auszudrücken, und alle Tests machen es für einen zukünftigen Betreuer sehr einfach zu sehen, wie der Code aufgerufen werden soll und was zurück zu erwarten ist.

In den Testfällen werden Versionen der Spezifikation ausgeführt, und Sie können sehr, sehr einfach sehen, wie Sie Ihre API aufrufen. Dies ist wahrscheinlich die nützlichste Form der "WIE" -Dokumentation, die ich bisher gesehen habe (vergleiche mit der "WARUM" -Dokumentation wie JavaDoc), da Sie sicher sind, dass sie korrekt ist (andernfalls würde der Test fehlschlagen).

In letzter Zeit musste ich einen skriptfähigen FTP-Client mit einer Vielzahl von Optionen warten, die sich alle auf die Funktionsweise der Anwendung auswirken. TDD wurde kürzlich für neue Funktionen eingeführt und die große Testsuite ermöglicht es uns, Hotfixes durchzuführen, während wir sicher sind, dass die verwendete Funktionalität weiterhin wie erwartet funktioniert. Mit anderen Worten, dieser Übergang hat sich sehr schnell ausgezahlt.


8
Diese Antwort scheint völlig neben der Frage zu stehen, da die Frage Beispiele aus der Praxis erfordert . Aber da drei Leute dachten "diese Antwort ist nützlich", muss ich etwas vermissen.

3
Einverstanden, aber mir fehlt der Ruf, abzustimmen. Dies ist nur die "TDD gibt bessere Ergebnisse" ohne Beispiel eines TDD-abgeleiteten Projekts in der Wartung, um die Antwort zu sichern, die ich vermeiden wollte.
James

Jetzt, da mir mehrere Leute zugestimmt haben, wage ich es, nicht zu stimmen. Würden Sie einen Wähler oder den Autor bitten, sich zu melden und uns zu sagen, warum dies eine gute Antwort ist?

@delnan "Ich wage downvote" - eine interessante Wortwahl. Fiel die Bearbeitung Ihrem Geschmack?

Ja, ich habe meine Downvote entfernt, nachdem ich es bemerkt habe.

5

Wie wertvoll ein bestimmter Testansatz ist, hängt davon ab, wie geschäftskritisch das zu entwickelnde System ist und wie sehr ein anderes geschäftskritisches System davon abhängt. Ein einfaches Gästebuch-Skript für Ihre Website kann kaum als geschäftskritisch eingestuft werden. Wenn jedoch die Website, auf der es ausgeführt wird, durch einen Fehler, der eine ungefilterte Eingabe in die Datenbank ermöglichte und auf der diese Website einen wichtigen Service bietet, möglicherweise gefährdet wird, wird sie plötzlich viel umfangreicher wichtig, dass das Gästebuch-Skript gründlich getestet wird. Gleiches gilt auch für Framework / Bibliothekscode. Wenn Sie ein Framework mit einem Fehler entwickeln, weist jede Anwendung, die diese Framework-Funktion verwendet, denselben Fehler auf.

Testgetriebene Entwicklung gibt Ihnen zusätzliche Sicherheit, wenn es um Tests geht. Wenn Sie die Tests neben oder sogar nach dem Code schreiben, den Sie testen möchten, besteht ein echtes Risiko, dass Sie die Tests falsch verstehen. Wenn Sie zuerst alle Tests schreiben, kann die interne Funktionsweise des Codes keinen Einfluss darauf haben, wofür Sie Tests schreiben. Daher besteht weniger die Möglichkeit, dass Sie versehentlich Tests schreiben, die glauben, dass eine bestimmte fehlerhafte Ausgabe korrekt ist.

Testgetriebene Entwicklung ermutigt Ihre Entwickler auch, Code zu schreiben, der einfach zu testen ist, da sie sich nicht noch mehr Arbeit geben möchten! Code, der einfach zu testen ist, ist in der Regel einfach zu verstehen, wiederzuverwenden und zu warten.

Und die Wartung ist der Ort, an dem Sie die Vorteile von TDD wirklich nutzen können. Der überwiegende Teil des Programmieraufwands für Software ist wartungsbedingt. Dies bedeutet, Änderungen am Live-Code vorzunehmen, um ihm neue Funktionen zu verleihen, Fehler zu beheben oder ihn an neue Situationen anzupassen. Wenn Sie solche Änderungen vornehmen, möchten Sie sicherstellen, dass die von Ihnen vorgenommenen Änderungen den gewünschten Effekt haben, und, was noch wichtiger ist, dass sie keine unerwarteten Auswirkungen haben. Wenn Sie über eine vollständige Testsuite für Ihren Code verfügen, können Sie leicht überprüfen, ob alle vorgenommenen Änderungen nichts anderes beschädigen. Wenn die vorgenommenen Änderungen etwas anderes beschädigen, können Sie den Grund dafür schnell ermitteln. Die Vorteile sind langfristig.

Sie haben in Ihrer Frage Folgendes gesagt:

Ich sehe einen gewissen Vorteil darin, Tests für einige Dinge zu schreiben, aber nur für sehr wenige. Und obwohl mir die Idee gefällt, den Test zuerst zu schreiben, verbringe ich wesentlich mehr Zeit damit, meine Tests zu debuggen, damit sie sagen, was ich wirklich meine, als tatsächlichen Code zu debuggen. Dies liegt wahrscheinlich daran, dass der Testcode oft wesentlich komplizierter ist als der Code, den er testet. Ich hoffe, dies ist nur Unerfahrenheit mit den verfügbaren Tools (in diesem Fall rspec).

Dies scheint mir zu suggerieren, dass Sie nicht ganz auf die Probe gestellt werden. Ein Unit-Test soll extrem einfach sein, nur eine Folge von Methodenaufrufen, gefolgt von einer Aussage, um das erwartete Ergebnis mit dem tatsächlichen Ergebnis zu vergleichen. Sie sollten einfach sein, da Fehler in Ihren Tests katastrophal wären. Wenn Sie Schleifen, Verzweigungen oder andere Programmfunktionen in den Test einführen, ist es wahrscheinlicher, dass der Test einen Fehler enthält. Wenn Sie viel Zeit mit dem Debuggen von Tests verbringen, bedeutet dies, dass Ihre Tests zu kompliziert sind und Sie sie vereinfachen sollten.

Wenn die Tests nicht vereinfacht werden können, deutet allein diese Tatsache darauf hin, dass mit dem getesteten Code etwas nicht stimmt. Wenn Ihre Klasse beispielsweise über lange Methoden, Methoden mit vielen if / elseif / else- oder switch-Anweisungen oder eine große Anzahl von Methoden verfügt, deren komplexe Interaktionen vom aktuellen Status der Klasse bestimmt werden, müssen die Tests zwangsläufig äußerst komplex sein um vollständige Codeabdeckung bereitzustellen und alle Eventualitäten zu testen. Wenn Ihre Klasse fest codierte Abhängigkeiten von anderen Klassen aufweist, erhöht dies erneut die Anzahl der Rahmen, zu denen Sie springen müssen, um Ihren Code effektiv zu testen.

Wenn Sie Ihre Klassen klein und stark fokussiert halten, kurze Methoden mit wenigen Ausführungspfaden verwenden und versuchen, den internen Status zu beseitigen, können die Tests vereinfacht werden. Und das ist der springende Punkt. Guter Code ist von Natur aus leicht zu testen. Wenn der Code nicht einfach zu testen ist, stimmt wahrscheinlich etwas nicht.

Unit-Tests zu schreiben ist etwas, das Ihnen auf lange Sicht zugute kommt. Wenn Sie diese vermeiden, sparen Sie sich einfach Ärger für später. Sie kennen das Konzept der technischen Verschuldung vielleicht nicht, aber es funktioniert ähnlich wie die Finanzverschuldung. Keine Tests schreiben, keinen Code kommentieren, in fest codierte Abhängigkeiten schreiben und so weiter, um Schulden zu machen. Sie "leihen" sich die Zeit, indem Sie frühzeitig Abstriche machen, und dies kann Ihnen helfen, einen engen Termin einzuhalten, aber die Zeit, die Sie früher im Projekt sparen, ist ausgeliehen. Jeder Tag, der vergeht, ohne den Code zu bereinigen, richtig zu kommentieren oder eine Testsuite zu erstellen, kostet Sie Interesse. Je länger es dauert, desto mehr Zinsen fallen an. Schließlich werden Sie feststellen, dass Ihr Code zu einem Wirrwarr geworden ist, an dem Sie keine Änderungen vornehmen können, ohne unbeabsichtigte Konsequenzen auszulösen.

Sie könnten daran denken, Unit-Tests frühzeitig zu schreiben und sie als eine Form des "technischen Kredits" auf dem neuesten Stand zu halten. Sie investieren Zeit in die Bank, indem Sie sie frühzeitig in das Befolgen bewährter Praktiken investieren. Sie werden später Interesse an dieser Vorausschau haben, wenn Sie die Wartungsphase des Projekts erreichen. Wenn Sie eine Änderung vornehmen möchten, können Sie auf einfache Weise die Richtigkeit der Änderung überprüfen und feststellen, dass sie keine unerwünschten Nebenwirkungen hat. Außerdem können Sie Aktualisierungen schnell und unkompliziert herausbringen. Wenn Fehler auftauchen, können Sie einen neuen Komponententest hinzufügen, der den Fehler auslöst, und dann den Fehler im Code beheben. Wenn Sie den Unit-Test das nächste Mal ausführen, können Sie überprüfen, ob der Fehler behoben wurde und keine weiteren Probleme aufgetreten sind. Darüber hinaus werden Sie "Regressionen" vermeiden,

TL: DR - Ja, sie sind eine echte Hilfe, aber eine Investition. Die Vorteile werden erst später ersichtlich.


1
Ich habe mich vor Monaten für diese Logik entschieden. Ich liebe die Idee hinter TDD. Ich finde die Realität ein bisschen beunruhigend. Außerdem fällt mir auf, dass es auch hier keine konkreten Beispiele gibt, bei denen sich die Vererbung eines TDD-basierten Projekts ausgezahlt hat. Sind Sie tatsächlich zu einer alten Codebasis zurückgekehrt, die eine Reihe von Unit-Tests hatte und die sich ausgezahlt hat?
James

Leider nicht, denn niemand scheint Unit-Tests zu erstellen, zumindest nicht mit dem Code, den ich von früheren Entwicklern geerbt habe. Mein Leben wäre verdammt viel einfacher gewesen, wenn sie es getan hätten. Ich würde vorschlagen, dass Sie sich das Buch im Link ansehen, das Beispiele aus der Praxis enthält, obwohl es sich eher um PHP als um Rails handelt. amazon.com/…
GordonM

Ich bin ein großer Kritiker des allgemeinen Gebrauchs, aber ich würde niemanden dafür beschuldigen, diesen Ansatz in einem eingebetteten oder kritischen Finanzsystem zu verwenden.
Erik Reppen

4

Ich benutze TDD ziemlich oft bei der Arbeit. Ich habe die Erfahrung gemacht, dass TDD sich rechtfertigt, weil Sie keine zusätzliche Zeit oder Mühe aufwenden , sondern es sparen .

  • Da ich TDD verwende, verbringe ich viel weniger Zeit mit dem Debuggen oder Ähnlichem. Es funktioniert nur von Anfang an, weil ich produktiven Code nicht als geschrieben betrachte, solange die Tests nicht bestanden werden.

  • QA meldet viel weniger Fehler, so dass wir Kosten für die Reparatur unseres Codes nach einer Veröffentlichung sparen. Dies liegt daran, dass Sie mit TDD keinen Code ohne Test schreiben können, sodass die Codeabdeckung viel besser ist.

  • Ich kann meinen (produktiven) Code viel häufiger und schneller ausführen, da ich nicht den gesamten Anwendungsserver starten muss. Das Starten des Komponententests ist um eine Größenordnung schneller. Natürlich profitiere ich nur dann davon, wenn der Test bereits ausführbar ist, wenn ich den produktiven Code ausprobieren möchte. Wenn die Tests danach kommen, wird dieser Vorteil verfehlt.

  • Ich mache viel weniger manuelle Tests. Meine Kollegen, die TDD nicht üben, verbringen viel Zeit damit, durch die Anwendung zu klicken, bis sie den Punkt erreichen, an dem der neue Code ausgeführt wird. Ich teste nur einmal manuell, kurz bevor ich mich zur Versionskontrolle begebe.

  • Selbst wenn ich einen Debugger verwende, ist es viel schneller, die Ausführung eines Tests zu debuggen, als die gesamte Anwendung.

Vielleicht denken Sie an Unit-Tests als Regressionstests. Das ist einer ihrer Ziele, aber das Verständnis, dass sie ein Werkzeug für die Entwicklung sind, macht sie viel lohnender.


Qualität ist kostenlos!
MathAttack

2
Schlechte Qualität ist teuer!
Wolfgang,

3

Ein weiterer Vorteil (zusätzlich zu denjenigen, die von den anderen Personen, die geantwortet haben, erwähnt wurden) tritt ein, wenn Kundenakzeptanztester oder (himmlische) Produktionsbenutzer einen Fehler entdecken. Verwandeln Sie den Fehlerbericht in einen TDD-Test für die Klasse, die anscheinend einen Fehler aufweist. Pass auf, dass es versagt. Repariere es. Pass auf, wie es vergeht. Dann wissen Sie, dass Sie den Fehler behoben haben. Diese Technik hat mir Stunden gespart.


2

Nun, ich weiß, dass ich persönlich davon profitiere, dass ich doppelt so schnell bin wie meine Kollegen und weniger als die Hälfte der Fehler schreibe, die sie machen, weil sie KEIN TDD machen. Leute, die wahrscheinlich sogar besser sein sollten als ich ... Ich übertreffe sie um mindestens den Faktor 2.

Ich bin nicht gleich dahin gekommen. Ich kann ziemlich gut Code von der Manschette schreiben und ohne Geschirr. Es schien wie eine große Verschwendung, all diesen zusätzlichen Mist zu schreiben. Aber es macht mehrere Dinge, einschließlich (nicht exklusiv):

  • Erzwingen eines Designs, das auf Entkopplung und Wiederverwendung ausgerichtet ist (alles muss in einem Komponententest wiederverwendet werden).
  • Bereitstellung einer Plattform zum Entwickeln von Code in kleinen Stücken und Modulen, damit ich nicht alles herausfinden und fertig stellen muss, bevor ich einen einfachen Test "Kompiliert es überhaupt und nimmt Eingaben an" durchführe.
  • Bereitstellung einer schnellen Testplattform zum Vornehmen von Änderungen, wenn Benutzer Funktionsänderungen fordern, die ich nicht erwartet hatte.

Ein Beispiel für dieses spätere Stück ist ein Projekt, an dem ich gerade arbeite. Der Lead entschied sich plötzlich, das Kommunikationsprotokoll, das es aus so ziemlich keinem Grund verwendete, GESAMT neu zu schreiben. Ich konnte auf diese Änderung in 2 Stunden reagieren, da ich mich bereits von allem anderen abgekoppelt hatte und es bis zum allerletzten Binden völlig selbständig bearbeiten und den Testschritt integrieren konnte. Die meisten meiner Kollegen wären wahrscheinlich einen Tag oder länger dabei gewesen, weil ihr Code nicht entkoppelt worden wäre und sie sich hier und da überall geändert hätten ... alles kompiliert hätten ... Integrationstests ... wiederholen, wiederholen ... dauert so viel länger und ist bei weitem nicht so stabil.


2

Die Antwort ist ja. In meiner Firma entwickeln wir seit über 20 Jahren eine C ++ - Anwendung. Letztes Jahr sind wir in einigen neuen Modulen auf TDD eingestiegen, und die Fehlerraten sind erheblich gesunken. Es hat uns so gut gefallen, dass einige von uns sogar jedes Mal, wenn wir dort etwas ändern, Tests zum Legacy-Code hinzufügen.

Darüber hinaus wurde ein ganzes Modul von Anfang bis Ende fertiggestellt und durchlief die Produktion, ohne jemals einen Fehler aufzuzeigen (und es ist auch ein kritisches Modul). Die Entwicklung verlief dabei schneller als üblich, denn normalerweise würde ein Modul "fertig" sein, nur um vier- bis fünfmal nach dem Betatest zur Behebung von Fehlern zurückzukehren. Es war eine wesentliche Verbesserung, und die Entwickler waren auch über das neue Verfahren zufriedener.

Ich habe nicht viel mit Rails TDD gemacht, aber ich habe viel mit C ++, C #, Java und Python gemacht. Ich kann Ihnen sagen, dass es definitiv funktioniert. Ich vermute, dass Sie viel Zeit damit verbringen, über Testnamen nachzudenken, weil Sie nicht sicher genug sind. Schreiben Sie zuerst Ihren Test, aber lassen Sie Ihrer Kreativität freien Lauf ...

Mir ist aufgefallen, dass Sie sich ein bisschen weniger für "Wie soll ich diesen Test benennen ... argh!" Interessieren, wenn Sie den Dreh erst einmal richtig verstanden haben Tests zur Anpassung an die aktuelle Situation.

Zeit für einen Tipp

Tipp 1

Ich denke, der Tipp, der Ihnen am meisten helfen sollte, ist, sich nicht so viele Sorgen zu machen. Eines der schönsten Dinge an TDD ist, dass es Ihnen Mut macht, Dinge zu ändern, die bereits geschrieben sind und funktionieren. Und das schließt die Tests ein.

Tipp 2

Starten Sie neue Klassentests mit einem einfachen "canCreate" -Test, um Ihre Meinung in die richtige Richtung zu lenken, wie in "Ok, ich arbeite gerade an dieser Klasse ... richtig."

Fügen Sie dann mehr Tests hinzu, aber nur einen nach dem anderen, und stellen Sie sicher, dass jeder von Ihnen erstellte Test der nächst einfachere Fall ist, der Ihnen zu diesem Zeitpunkt in den Sinn kommt (denken Sie nicht länger als 30 Sekunden darüber nach, und legen Sie dann eine Zeitüberschreitung fest mit dem besten, was du zu diesem Zeitpunkt hast).

Und merke dir

Machen Sie sich keine Sorgen, bestehende Tests zu überarbeiten oder veraltete oder überflüssige zu entfernen. Nicht viele Leute erkennen dies, aber in TDD erhalten Sie tatsächlich 2 Sicherheitsnetze zum Preis von 1. Ihre Tests sind ein Sicherheitsnetz für Änderungen des Produktionscodes, aber Ihr Produktionscode ist auch ein Sicherheitsnetz für die Überarbeitung der Tests. Die Beziehung ist gegenseitig. Es ist eigentlich ein guter Fall von enger Kopplung.

Versuchen Sie es noch einmal. Und lassen Sie mich empfehlen, Clean Code Casts anzusehen , insbesondere solche über TDD.


1

Reales, nicht triviales Beispiel:

Ich musste eine Datenstrukturtransformationsfunktion schreiben. Die Eingabe wäre eine Datenstruktur (tatsächlich eine verschachtelte Datenstruktur, ähnlich wie ein Baum) und die Ausgabe wäre eine ähnliche Datenstruktur. Ich konnte mir die tatsächliche Transformation in meinem Kopf nicht vorstellen. Einer der Hauptvorteile von TDD (für mich jedenfalls) ist die Durchsetzung von Babyschritten, wenn Sie nicht wissen, wie Sie vorgehen sollen (siehe Kent Becks "TDD am Beispiel"). Da ich nicht wusste, wohin das führen würde, begann ich mit den einfachen Basisfällen wie leeren oder trivialen Eingaben und arbeitete mich bis zu komplizierteren Fällen vor, bis ich dachte, ich hätte sie alle abgedeckt. Am Ende hatte ich einen funktionierenden Algorithmus und die Tests, die dies bewiesen haben. Die Tests beweisen nicht nur, dass meine Implementierung gerade funktioniert, sie hindern mich auch daran, später irgendetwas zu vermasseln.


-1

Ich mag es nicht, blindlings generischen Ratschlägen zu folgen, weil ich nicht glaube, dass es einen Vorschlag gibt, der die meisten Entwickler dabei unterstützt, produktiver zu werden und Fehler in Anwendungen zu reduzieren. Je mehr Sie sich Ihrer Erfahrung nach um die Qualität kümmern, desto mehr verlieren Sie an der Menge der bereitgestellten neuen Funktionen. Das Maß an Wichtigkeit, das Sie der Qualität im Vergleich zur Lieferfähigkeit beimessen möchten, hängt also tatsächlich von Ihrem Produkt und Ihrer aktuellen Strategie ab, und höchstwahrscheinlich entscheidet jemand anderes strategisch, was für den Moment wichtiger ist: Robustheit oder Lieferfähigkeit.

Auch diese Entscheidung ist nicht schwarz oder weiß. Höchstwahrscheinlich müssen einige Teile Ihrer Anwendung robust sein, andere nicht. Wenn Sie herausgefunden haben, welche Teile ein hohes Maß an Qualität aufweisen sollten, sollten Sie sich aus der Sicht des Testens darauf konzentrieren, da Sie für diese Teile eine hohe Qualität sicherstellen möchten.

Alles, was ich bisher gesagt habe, hat nichts mit TDD zu tun, insbesondere im Sinne des Schreibens von Tests vor der Implementierung, aber ich halte es für wichtig, die Vorteile des Testens von Code gegenüber dem Schreiben der Tests als Erstes zu unterscheiden.

Sobald Sie die Vorteile des Testens selbst, ob TDD oder nicht, verstanden haben, können Sie die Teststrategie für den Code erörtern, der von den Tests abgedeckt werden soll. Einige Leute werden argumentieren, dass, wenn Sie die Tests später schreiben, Sie einige Bedingungen in Ihren Tests verpassen, aber ich glaube, Sie sollten derjenige sein, der bewertet, ob das auf Sie zutrifft. Das trifft auf mich sicher nicht zu.

Also, hier ist, wie es bei mir funktioniert. Grundsätzlich gibt es zwei Situationen, in denen ich Tests schreiben muss: Sie verbessern nur die Qualität oder beschleunigen die Entwicklung einiger Funktionen. In einer Situation, in der ich Tests schreibe, gibt es keine neuen Funktionen im Backlog, und ich kann dann entscheiden, die Leistung der Anwendung zu verbessern, die Codebasis zu vereinfachen oder die Testsuite zu verbessern. Eine andere Situation ist die Notwendigkeit, einen soliden Arbeitscode zu haben, in dem Bugs einen ausreichenden Einfluss auf die echten Kunden haben. Ein weiterer Zweck ist das Testen von komplexem Code, der bei der Arbeit leicht zu knacken ist. Zum Beispiel gibt es eine QueryBuilder-Klasse in meiner Codebasis, die sich um viele Anwendungsfälle kümmert, und es wäre einfach, einige davon zu brechen, während ein Fehler behoben oder eine neue Funktion hinzugefügt wird.

Schließlich gibt es den Fall, dass das Schreiben der Tests es mir ermöglicht, eine Funktion schneller zu schreiben, als die Tests überhaupt nicht zu schreiben. Dass QueryBuilder auch ein Fall war, in dem diese Regel ebenfalls angewendet wurde, bedeutet jedoch nicht, dass TDD auch der beste Weg ist. Ein weiteres Beispiel für TDD, das zur Steigerung der Entwicklungsgeschwindigkeit beiträgt, ist das Testen der Excel-Generierung, während Sie in der realen Anwendung möglicherweise jedes Mal mehrere Schritte ausführen müssen, wenn Sie eine bestimmte Bedingung in der Generierung testen möchten. Oder wenn Sie einige Datensätze erstellen müssen, um ein Feature zu testen, und es schwierig oder unmöglich ist, sie manuell zu löschen, nachdem Sie den Code manuell getestet haben.

Wenn es für Sie einfacher ist, die Schritte zum programmgesteuerten Ausführen von Code aus der Entwicklungsphase (durch Tests) zu reproduzieren, können Sie dies tun. Wenn es jedoch komplizierter ist, den Test zu schreiben, als ihn manuell zu testen, müssen Sie sich entscheiden, ob es an der Zeit ist, sich auf die Qualität zu konzentrieren, oder ob Sie viele Anfragen in Ihrem Backlog haben und jemand im Unternehmen es wahrscheinlich besser wissen und Sie lassen wird wissen, wo Sie sich entsprechend ihrem aktuellen Bedarf und ihrer Unternehmensstrategie konzentrieren sollten.

In einer idealen Welt wird jeder Code getestet, aber man kann nicht so tun, als gäbe es keinen Kompromiss, und davon ausgehen, dass TDD immer der beste und einzige Weg ist. Wie bei allen Best Practices müssen Sie sich immer auf das konzentrieren, was für das Unternehmen, für das Sie arbeiten, am besten ist, anstatt auf das, was für Sie besser ist. Sobald Sie sich selbstständig gemacht haben, können Sie sich jederzeit für eine TDD entscheiden, wenn Sie der Meinung sind, dass dies der beste Weg ist. Wenn Ihr Unternehmen der Meinung ist, dass der gesamte Code getestet werden sollte, müssen Sie Tests für den gesamten Code schreiben, den Sie schreiben. In den meisten Fällen müssen Sie sich jedoch einen Überblick verschaffen und die Kompromisse verstehen, bevor Sie eine Entscheidung treffen. Tut mir leid, aber dies ist keine exakte Wissenschaft und es gibt keine einfache (oder harte) Einheitslösung, die Sie jedes Mal befolgen sollten.

Genau wie bei Designmustern. Verstehe, wie sie funktionieren und warum sie geschaffen wurden und welche Probleme sie lösen und was ihre Nachteile sind. Das Verständnis der Argumentation ist viel wichtiger, als sich an die vorgeschlagenen Lösungen zu erinnern. Was heute ein teurer Vorgang ist, kann morgen mit anderen Technologien problemlos erreicht werden. Wenn die Voraussetzung für eine gut etablierte Lösung nicht mehr gültig ist, ist die Lösung höchstwahrscheinlich nicht mehr die beste. Wenn sich die Anforderungen, die verfügbare Technologie oder die Strategie des Unternehmens geändert haben, sollten Sie Ihre Toolbox immer neu bewerten. In diesem Fall müssen Sie verstehen, warum Sie die einzelnen Pfade zuerst ausgewählt haben, anstatt sie als die besten Optionen für die Gewährung zu betrachten.


dies versucht nicht einmal, die gestellte Frage zu beantworten: "Haben wir endlich Beispiele, die belegen, dass die Auszahlung echt ist? Hat jemand tatsächlich Code geerbt oder ist er auf Code zurückgegangen, der mit TDD entworfen / entwickelt wurde und einen vollständigen Satz von Komponententests hat und tatsächlich eine Auszahlung gefühlt? "
gnat

1
Es antwortet, aber da Sie meine Meinung nicht teilen, geben Sie -1 an :) Grundsätzlich wird jeder, der nicht versucht, die Werte von TDD zu zeigen, aus Ihrer Sicht eine unerwünschte Antwort geben;) Lassen Sie mich raten . Du bist ein TDD-Evangelisator, oder? :) Die eigentliche Frage des Autors ist übrigens, ob sich TDD auszahlt oder nicht. Sie müssen TDD nicht üben, um darauf zu antworten. Lohnt sich Fortran für das Schreiben von Web-Apps? Hast du es versucht, bevor du antwortest?
Rosenfeld

Ich habe keine Meinung zu TDD und verwende keine Stimmen als "Gefällt mir" oder "Gefällt mir nicht" (es ist eine Frage-Antwort-Seite, keine Facebook-Seite). Nach meiner Lektüre geht diese "Antwort" einfach überhaupt nicht auf die gestellte Frage ein, weder positiv noch negativ
gnat

Aus meiner Sicht ist dies keine technische Frage wie "Wie mache ich X mit Nginx?". Auf solche Fragen gibt es richtige Antworten, aber nicht auf solche qualitativen und subjektiven Fragen, wenn der Autor tatsächlich die Meinung anderer über TDD wissen will und ob es sich lohnt. Das war mein Versuch, meine Sichtweise zu zeigen. Ich habe keine Ahnung, wie eine Antwort die richtige sein könnte, da sie mir alle nur als persönliche Meinungen erscheinen. Sie können nicht effektiv messen, ob TDD wert ist oder nicht. Alle Artikel, die dies versuchen, sind grundsätzlich falsch.
Rosenfeld

„Diese Seite ist all Tour Antworten bekommen Es ist kein Diskussionsforum ....“
gnat
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.