Ich bin ein Einzelentwickler mit einer ziemlich zeitlich begrenzten Arbeitsumgebung, in der die Entwicklungszeit normalerweise zwischen 1 und 4 Wochen pro Projekt liegt, abhängig von den Anforderungen, der Dringlichkeit oder beiden. Zu einem bestimmten Zeitpunkt bearbeite ich ungefähr 3-4 Projekte, von denen einige überlappende Zeitleisten haben.
Erwartungsgemäß leidet die Codequalität. Ich habe auch keine formalen Tests; Es geht normalerweise so lange durch das System, bis es etwas bricht. Infolgedessen kann eine beträchtliche Anzahl von Fehlern in die Produktion gelangen, die ich beheben muss, und die wiederum meine anderen Projekte zurücksetzen.
Hier kommen Unit-Tests ins Spiel. Wenn alles richtig gemacht wird, sollten die Fehler, geschweige denn die, die in die Produktion flüchten, auf ein Minimum reduziert werden. Auf der anderen Seite kann das Schreiben von Tests viel Zeit in Anspruch nehmen, was sich bei zeitlich begrenzten Projekten wie meinem nicht gut anhört.
Die Frage ist, wie viel Zeitunterschied das Schreiben von Unit-Test-Code gegenüber ungetestetem Code bedeuten würde, und wie weitet sich dieser Zeitunterschied mit zunehmendem Projektumfang aus?
quelle
Antworten:
Je später Sie testen, desto mehr kostet es, Tests zu schreiben.
Je länger ein Fehler lebt, desto teurer ist die Behebung.
Das Gesetz der sinkenden Rendite stellt sicher, dass Sie sich selbst in Vergessenheit geraten lassen und sicherstellen können, dass es keine Bugs gibt.
Buddha lehrte die Weisheit des Mittelwegs. Tests sind gut. Es gibt so etwas wie zu viel Gutes. Der Schlüssel ist in der Lage zu erkennen, wenn Sie aus dem Gleichgewicht sind.
Jede Codezeile, die Sie ohne Tests schreiben, verursacht erheblich höhere Kosten für das Hinzufügen von Tests, als wenn Sie die Tests vor dem Schreiben des Codes geschrieben hätten.
Jede Codezeile ohne Tests ist erheblich schwieriger zu debuggen oder neu zu schreiben.
Jeder Test, den Sie schreiben, braucht Zeit.
Es wird einige Zeit dauern, bis jeder Fehler behoben ist.
Die Gläubigen werden Ihnen sagen, dass Sie keine einzige Codezeile schreiben sollen, ohne zuerst einen nicht bestandenen Test zu schreiben. Der Test stellt sicher, dass Sie das Verhalten erhalten, das Sie erwarten. Damit können Sie den Code schnell ändern, ohne sich Gedanken über Auswirkungen auf den Rest des Systems machen zu müssen, da der Test beweist, dass das Verhalten dasselbe ist.
Sie müssen all das gegen die Tatsache abwägen, dass Tests keine Funktionen hinzufügen. Produktionscode fügt Funktionen hinzu. Und Funktionen sind das, was die Rechnungen bezahlen.
Pragmatisch gesehen füge ich alle Tests hinzu, mit denen ich durchkommen kann. Ich ignoriere Kommentare zugunsten von Tests. Ich vertraue nicht einmal Code zu tun, was ich denke, dass es tut. Ich vertraue Tests. Aber ich war bekannt dafür, dass ich gelegentlich Hagelwurf mache und Glück habe.
Viele erfolgreiche Codierer führen jedoch keine TDD durch. Das heißt nicht, dass sie nicht testen. Sie bestehen einfach nicht darauf, dass jede Codezeile einen automatisierten Test hat. Selbst Onkel Bob gibt zu, dass er seine Benutzeroberfläche nicht testet. Er besteht auch darauf, dass Sie die gesamte Logik aus der Benutzeroberfläche entfernen.
Als Fußballmetapher (das ist American Football) ist TDD ein gutes Grundspiel. Nur manuelles Testen, bei dem Sie eine Menge Code schreiben und hoffen, dass es funktioniert, ist ein vorübergehendes Spiel. Sie können entweder gut sein. Ihre Karriere wird die Playoffs nicht schaffen, wenn Sie nicht beides können. Erst wenn Sie wissen, wann Sie welche auswählen müssen, wird das Superbowl zu etwas Besonderem werden. Aber wenn Sie einen Schubs in eine bestimmte Richtung brauchen: Die Beamten rufen mich häufiger an, wenn ich vorbeigehe.
Wenn Sie TDD ausprobieren möchten, empfehle ich dringend, dass Sie üben, bevor Sie versuchen, es bei der Arbeit zu tun. TDD auf halbem Weg gemacht, halbherzig und halbherzig ist ein wichtiger Grund, warum manche es nicht respektieren. Es ist, als würde man ein Glas Wasser in ein anderes gießen. Wenn Sie sich nicht festlegen und es schnell und vollständig tun, träufeln Sie am Ende Wasser über den Tisch.
quelle
Ich stimme dem Rest der Antworten zu, aber um die Frage nach dem Zeitunterschied direkt zu beantworten .
Roy Osherove hat in seinem Buch The Art of Unit Testing, zweite Ausgabe, Seite 200 eine Fallstudie durchgeführt, in der Projekte ähnlicher Größe mit ähnlichen Teams für zwei verschiedene Kunden implementiert wurden, bei denen ein Team Tests durchführte und das andere nicht.
Seine Ergebnisse waren wie folgt:
Am Ende eines Projekts treten also sowohl weniger Zeit als auch weniger Fehler auf. Das hängt natürlich davon ab, wie groß ein Projekt ist.
quelle
Ich kenne nur eine Studie, die dies in einer "realen Umgebung" untersucht hat: Qualitätsverbesserung durch testgetriebene Entwicklung: Ergebnisse und Erfahrungen von vier Industrieteams . Es ist teuer, dies auf vernünftige Weise zu tun, da es im Grunde bedeutet, dass Sie dieselbe Software zweimal (oder im Idealfall sogar öfter) mit ähnlichen Teams entwickeln und dann alle außer einem wegwerfen müssen.
Die Ergebnisse der Studie waren eine Verlängerung der Entwicklungszeit zwischen 15% und 35% (was nicht annähernd der von TDD-Kritikern häufig angegebenen 2-fachen Zahl entspricht) und eine Verringerung der Defektdichte vor der Freigabe von 40% auf 90% (! ). Es ist zu beachten, dass alle Teams keine Erfahrung mit TDD hatten, sodass man davon ausgehen konnte, dass der Zeitanstieg zumindest teilweise auf das Lernen zurückzuführen ist und daher im Laufe der Zeit noch weiter sinken würde, was von der Studie jedoch nicht bewertet wurde.
Beachten Sie, dass es in dieser Studie um TDD geht und dass es sich bei Ihrer Frage um Unit-Tests handelt, bei denen es sich um sehr unterschiedliche Dinge handelt, die mir jedoch am nächsten kommen.
quelle
null
, Funktionieren über Imperativ, Codeverträge, statische Analyse, automatisches Refactoring, keine IoC-Container (aber DI) usw. Ich wette diesen Wert der Unit-Tests würde abnehmen (aber nicht verschwinden).Gut gemacht, kann die Entwicklung mit Komponententests schneller sein, auch ohne die Vorteile von Extras zu berücksichtigen, die beim Erkennen von Fehlern auftreten.
Tatsache ist, dass ich nicht gut genug bin, um meinen Code einfach arbeiten zu lassen, sobald er kompiliert ist. Wenn ich Code schreibe / ändere, muss ich den Code ausführen, um sicherzustellen, dass er das tut, was ich dachte. Bei einem Projekt sah das so aus:
Und natürlich dauerte es nach all dem normalerweise ein paar Hin- und Rückfahrten, um es richtig zu machen.
Was ist, wenn ich Unit-Tests verwende? Dann sieht der Prozess eher so aus:
Dies ist einfacher und schneller als das manuelle Testen der Anwendung. Ich muss die Anwendung immer noch manuell ausführen (damit ich nicht albern aussehe, wenn ich eine Arbeit einreiche, die eigentlich gar nicht funktioniert), aber zum größten Teil habe ich die Probleme bereits behoben, und ich bin es nur Überprüfung an diesem Punkt. Normalerweise mache ich diese Schleife noch enger, indem ich ein Programm verwende, das meine Tests beim Speichern automatisch wiederholt.
Dies hängt jedoch davon ab, ob Sie in einer testfreundlichen Codebasis arbeiten. Viele Projekte, auch solche mit vielen Tests, erschweren das Schreiben von Tests. Wenn Sie jedoch daran arbeiten, können Sie über eine Codebasis verfügen, die durch automatisierte Tests einfacher zu testen ist als durch manuelle Tests. Als Bonus können Sie die automatisierten Tests beibehalten und ausführen, um Regressionen zu vermeiden.
quelle
Obwohl es bereits viele Antworten gibt, wiederholen sie sich etwas und ich würde gerne eine andere Richtung einschlagen. Unit-Tests sind nur dann wertvoll, wenn sie den Unternehmenswert steigern . Das Testen zu Testzwecken (triviale oder tautologische Tests) oder um eine beliebige Metrik (wie die Codeabdeckung) zu treffen, ist Frachtkultprogrammierung.
Tests sind kostspielig, nicht nur in der Zeit, in der sie geschrieben werden müssen, sondern auch in der Wartung. Sie müssen mit dem Code, den sie testen, synchron gehalten werden, oder sie sind wertlos. Ganz zu schweigen von den Zeitkosten, die bei jeder Änderung anfallen. Dies ist kein Deal-Breaker (oder eine Entschuldigung dafür, nicht die wirklich notwendigen zu machen), sondern muss bei der Kosten-Nutzen-Analyse berücksichtigt werden.
Bei der Frage, ob (oder in welcher Form) eine Funktion / Methode getestet werden soll, sollten Sie sich also die Frage stellen, welchen Endbenutzerwert ich mit diesem Test erzeuge / absichere. Wenn Sie diese Frage nicht beantworten können, weg von der Oberseite des Kopfes , dann ist das Test wahrscheinlich nicht wert , die Kosten des Schreibens / aufrechterhalten wird . (oder Sie nicht verstehen , die Problem - Domäne, die eine ist waaaay größeres Problem als ein Mangel an Tests).
http://rbcs-us.com/documents/Why-Most-Unit-Testing-is-Waste.pdf
quelle
Dies hängt von der Person sowie der Komplexität und Form des Codes ab, mit dem Sie arbeiten.
Bei den meisten Projekten bedeutet das Schreiben von Komponententests für mich, dass ich die Arbeit etwa 25% schneller erledige. Ja, einschließlich der Zeit, um die Tests zu schreiben.
Weil die Tatsache ist, dass Software nicht fertig ist, wenn Sie den Code schreiben. Dies geschieht, wenn Sie es an den Kunden versenden und dieser damit zufrieden ist. Unit-Tests sind bei weitem die effizienteste Methode, die ich kenne, um die meisten Fehler zu erkennen, die meisten Fehler zum Debuggen zu isolieren und das Vertrauen zu gewinnen, dass der Code gut ist. Sie müssen diese Dinge sowieso tun, also machen Sie sie gut.
quelle
Das Problem verschlimmert sich mit zunehmendem Alter des Projekts: Wenn Sie neue Funktionen hinzufügen und / oder vorhandene Implementierungen überarbeiten, müssen Sie erneut testen, was zuvor getestet wurde, um sicherzustellen, dass es weiterhin funktioniert. Für ein langlebiges (mehrjähriges) Projekt müssen Sie möglicherweise nicht nur die Funktionalität testen, sondern sie 100-mal und öfter erneut testen. Aus diesem Grund können Sie von automatisierten Tests profitieren . IMO ist es jedoch gut genug (oder sogar besser), wenn es sich um automatisierte Systemtests handelt und nicht um automatisierte Komponententests.
Ein zweites Problem ist, dass es schwieriger ist, Fehler zu finden und zu beheben, wenn sie nicht frühzeitig entdeckt werden. Wenn sich beispielsweise ein Fehler im System befindet und ich weiß, dass er einwandfrei funktioniert hat, bevor Sie Ihre letzte Änderung vorgenommen haben, konzentriere ich meine Aufmerksamkeit auf Ihre letzte Änderung, um zu sehen, wie der Fehler möglicherweise aufgetreten ist. Aber wenn ich nicht weiß, dass das System funktioniert hat, bevor Sie Ihre letzte Änderung vorgenommen haben (weil das System vor Ihrer letzten Änderung nicht ordnungsgemäß getestet wurde), kann der Fehler an einer beliebigen Stelle auftreten.
Das Obige gilt insbesondere für Deep Code und weniger für flachen Code, z. B. das Hinzufügen neuer Webseiten, wenn neue Seiten wahrscheinlich keine Auswirkungen auf vorhandene Seiten haben.
Nach meiner Erfahrung wäre das inakzeptabel und Sie stellen die falsche Frage. Anstatt zu fragen, ob Tests die Entwicklung beschleunigen würden, sollten Sie sich fragen, was die Entwicklung fehlerfreier machen würde.
Eine bessere Frage könnte sein:
Lernen ist ein zweistufiger Prozess: Lernen Sie, es gut genug zu machen, und lernen Sie dann, es schneller zu machen.
quelle
Einige Aspekte zu berücksichtigen, nicht in den anderen Antworten erwähnt.
Zusammenfassung
Wenn Sie mit tdd beginnen, ist es schwierig, den Status "Mehr Nutzen als Kosten" zu erreichen, solange Sie sich in einem "zeitlich begrenzten Arbeitsumfeld" befinden, insbesondere wenn es "clevere Manager" gibt, die Ihnen sagen, dass Sie "die teuren, nutzlosen" loswerden sollen Sachen testen "
Hinweis: Mit "Komponententest" meine ich "Module isoliert testen".
Hinweis: Mit "Regressionstests" meine ich
quelle
Programmierer unterschätzen, wie Menschen, die sich mit den meisten Aufgaben befassen, wie lange es tatsächlich dauert, diese zu erledigen. Unter diesem Gesichtspunkt kann ein Zeitaufwand von 10 Minuten für das Schreiben eines Tests als Zeitaufwand für das Schreiben von Tonnen von Code angesehen werden, während Sie in Wirklichkeit dieselbe Zeit damit verbracht hätten, denselben Funktionsnamen und dieselben Parameter wie während des Tests zu entwickeln . Dies ist ein TDD-Szenario.
Tests nicht zu schreiben, ist wie eine Kreditkarte zu haben; Wir neigen dazu, mehr Geld auszugeben oder mehr Code zu schreiben. Mehr Code hat mehr Fehler.
Anstatt sich für eine vollständige oder gar keine Codeabdeckung zu entscheiden, empfehle ich, sich auf den kritischen und komplizierten Teil Ihrer Anwendung zu konzentrieren und dort Tests durchzuführen. In einer Banking-App kann dies die Zinsberechnung sein. Ein Motordiagnose-Tool verfügt möglicherweise über komplexe Kalibrierungsprotokolle. Wenn Sie an einem Projekt gearbeitet haben, wissen Sie wahrscheinlich, was es ist und wo die Fehler sind.
Beginnen Sie langsam. Bauen Sie etwas Geläufigkeit auf, bevor Sie urteilen. Sie können immer aufhören.
quelle
Es gibt eine lange Geschichte von Programmierern, die TDD und andere Testmethoden bewerben. Ich werde mich nicht an ihre Argumente erinnern und ihnen zustimmen.
Ich würde sagen, dass das Testen gut ist, aber stellen Sie sicher, dass Sie früh testen und prüfen, wo der Gewinn liegt.
quelle
mainTest()
, das alle Testmodule aufruft, auszuführen, ist nicht wirklich schwierig.Ein oft übersehener Vorteil von TDD ist, dass die Tests als Schutz dienen, um sicherzustellen, dass Sie bei Änderungen keine neuen Fehler einführen.
Der TDD-Ansatz ist anfangs zweifellos zeitaufwändiger, aber der springende Punkt ist, dass Sie weniger Code schreiben , was bedeutet, dass weniger Dinge schief gehen. All diese Schnickschnack, die Sie oft einbauen, schaffen es natürlich nicht in die Codebasis.
Es gibt eine Szene im Film Swordfish, in der ein Hacker mit einer Waffe an seinem Kopf arbeiten muss, um sich zu erinnern, und ansonsten abgelenkt wird. Der Punkt ist, dass es viel einfacher ist zu arbeiten, wenn sich Ihr Headspace im Code befindet und Sie Zeit auf Ihrer Seite haben, anstatt Monate später, wenn ein Kunde Sie anschreit und andere Prioritäten gequetscht werden.
Entwickler verstehen, dass das Beheben von Fehlern später teurer ist, aber drehen Sie das auf den Kopf. Wenn Sie 500 US-Dollar pro Tag für die Codierung Ihres aktuellen Codes oder 1000 US-Dollar für die TDD-Codierung erhalten könnten, würden Sie der Person, die Ihnen das zweite Angebot unterbreitet, die Hand abbeißen. Je eher Sie das Testen nicht mehr als lästige Pflicht ansehen und es als Geldsparer ansehen, desto besser ist es für Sie.
quelle
Ich kann mich auf Ihre Erfahrung beziehen - unsere Codebasis hatte fast keine Tests und war größtenteils nicht testbar. Es dauerte buchstäblich eine Ewigkeit, um etwas zu entwickeln, und die Behebung von Produktivitätsfehlern kostbare Zeit für neue Funktionen.
Für eine teilweise Umschreibung habe ich mir geschworen, Tests für alle Kernfunktionen zu schreiben. Anfangs dauerte es erheblich länger und meine Produktivität litt merklich, aber danach war meine Produktivität besser als je zuvor.
Ein Teil dieser Verbesserung war, dass ich weniger Produktionsfehler hatte, was wiederum zu weniger Unterbrechungen führte -> ich hatte zu jeder Zeit einen besseren Fokus.
Darüber hinaus zahlt sich die Fähigkeit aus, Code isoliert zu testen UND zu debuggen - eine Reihe von Tests ist einem System, das nur mit manueller Einrichtung debuggt werden kann, bei weitem überlegen, z ein paar Dutzend Mal
Beachten Sie jedoch, dass die Produktivität zu Beginn abnimmt. Beginnen Sie also mit dem Testen eines Projekts, bei dem der Zeitdruck noch nicht verrückt ist. Versuchen Sie auch, es in einem Projekt auf der grünen Wiese zu starten. Das Testen älterer Codes durch Unit-Tests ist sehr schwierig. Es ist hilfreich, wenn Sie wissen, wie eine gute Testsuite aussieht.
quelle
Nur um vorherige Antworten zu ergänzen: Denken Sie daran, dass das Testen selbst kein Zweck ist. Der Zweck von Tests besteht darin, dass sich Ihre Anwendung im Verlauf der Evolution in unerwarteten Kontexten usw. erwartungsgemäß verhält.
Schreiben von Tests bedeutet daher nicht, alle Verhaltensweisen aller Endpunkte einer Entität zu beweisen. Dies ist ein häufiger Fehler. Viele Entwickler denken, dass sie alle Funktionen / Objekte / Methoden / Eigenschaften / etc testen müssen. Dies führt zu einer hohen Arbeitsbelastung und einer Reihe irrelevanter Codes und Tests. Dieser Ansatz ist bei großen Projekten üblich, bei denen sich die meisten Entwickler des ganzheitlichen Verhaltens nicht bewusst sind, sondern nur ihren Interaktionsbereich sehen können.
Der richtige Ansatz beim Umgang mit sparsamen Ressourcen und beim Testen ist ziemlich offensichtlich und vom gesunden Menschenverstand, aber nicht allgemein formalisiert: Investieren Sie die Ressourcen für die Testentwicklung zunächst in Funktionen auf hoher Ebene und gehen Sie schrittweise in Besonderheiten über . Das bedeutet, dass Sie sich als einsamer Entwickler irgendwann nicht nur auf Unit-Tests konzentrieren, sondern auch auf Funktionen / Integration / etc. Testen und je nach Ihren Zeitressourcen schrittweise in die wichtigsten einheitlichen Funktionen, wie Sie planen und berücksichtigen würden. Übergeordnete Tests bieten die erforderlichen Informationen, um übergeordnete / einheitliche Tests abzuwickeln und Ihre Testentwicklungsstrategie anhand der verfügbaren Ressourcen zu planen.
Beispielsweise möchten Sie eine Verarbeitungskette zunächst als Blackbox testen. Wenn Sie feststellen, dass ein Mitglied der Kette aufgrund eines Verhaltens ausfällt, bei dem ein extremer Zustand nicht berücksichtigt wurde, schreiben Sie die Tests, die die Funktionalität nicht nur für dieses Mitglied, sondern auch für andere garantieren. Dann liefern Sie. Im nächsten Zyklus stellen Sie fest, dass das Netzwerk manchmal ausfällt. Sie schreiben also Tests, die sich mit solchen Problemen befassen, auf die Module, die anfällig sein könnten. Und so weiter.
quelle