Testgetriebene Entwicklung (TDD) ist heutzutage groß. Ich sehe es oft als eine Lösung für eine Vielzahl von Problemen hier in der Programmers SE und in anderen Veranstaltungsorten. Ich frage mich, warum es funktioniert.
Aus technischer Sicht ist es mir aus zwei Gründen ein Rätsel:
- Der Ansatz "Write Test + Refactor Till Pass" sieht unglaublich anti-engineering aus. Wenn Bauingenieure diesen Ansatz beispielsweise für den Brückenbau oder Autodesigner für ihre Autos verwenden würden, würden sie ihre Brücken oder Autos mit sehr hohen Kosten umgestalten, und das Ergebnis wäre ein Flickwerk ohne durchdachte Architektur . Die "Refactor-till-Pass" -Richtlinie wird oft als Auftrag verstanden, die architektonische Gestaltung zu vergessen und alles Notwendige zu tun , um dem Test zu entsprechen. Mit anderen Worten, der Test und nicht der Benutzer legt die Anforderung fest. Wie können wir in dieser Situation gute "Fähigkeiten" in den Ergebnissen garantieren, dh ein Endergebnis, das nicht nur korrekt, sondern auch erweiterbar, robust, benutzerfreundlich, zuverlässig, sicher usw. ist? Das ist es, was Architektur normalerweise tut.
- Tests können nicht garantieren, dass ein System funktioniert. es kann nur zeigen, dass dies nicht der Fall ist. Mit anderen Worten, Tests können zeigen, dass ein System Fehler enthält, wenn ein Test nicht bestanden wird. Ein System, das alle Tests besteht, ist jedoch nicht sicherer als ein System, das diese nicht bestanden hat. Testabdeckung, Testqualität und andere Faktoren sind hier entscheidend. Die falschen Sicherheitsgefühle, die ein "all green" -Ergebnis für viele Menschen hervorruft, wurden in der Zivil- und Luftfahrtindustrie als äußerst gefährlich eingestuft, da dies als "das System ist in Ordnung" interpretiert werden kann, wenn es wirklich bedeutet, dass das System so gut ist als unsere Teststrategie ". Oft wird die Teststrategie nicht überprüft. Oder wer testet die Tests?
Zusammenfassend bin ich mehr besorgt über das "gesteuerte" Bit in TDD als über das "Test" Bit. Testen ist vollkommen in Ordnung; Was ich nicht verstehe, ist, das Design damit voranzutreiben.
Ich würde gerne Antworten erhalten, die Gründe dafür enthalten, warum TDD in der Softwareentwicklung eine gute Praxis ist und warum die oben erläuterten Probleme im Fall von Software nicht relevant (oder nicht relevant genug) sind. Danke.
Antworten:
Ich denke, hier gibt es ein Missverständnis. Beim Softwaredesign kommt das Design dem Produkt sehr nahe. Im Tiefbau, der Architektur, ist das Design vom eigentlichen Produkt entkoppelt: Es gibt Entwürfe, die das Design enthalten, die dann in das fertige Produkt verwirklicht werden und die durch einen enormen Zeit- und Arbeitsaufwand voneinander getrennt werden.
TDD testet das Design. Aber jedes Autodesign und jedes Gebäudedesign wird auch getestet. Die Konstruktionstechniken werden zuerst berechnet, dann im kleineren Maßstab getestet und dann im größeren Maßstab getestet, bevor sie in einem realen Gebäude ausgeführt werden. Als sie zum Beispiel H-Träger und die Last erfanden, stellten sie sicher, dass dies schon versucht wurde und noch einmal versucht wurde, bevor sie tatsächlich die erste Brücke damit bauten.
Entwürfe von Autos werden ebenfalls getestet, indem Prototypen entworfen werden, und zwar indem Dinge, die nicht genau richtig sind, angepasst werden, bis sie den Erwartungen entsprechen. Ein Teil dieses Prozesses ist jedoch langsamer, da Sie, wie Sie sagten, nicht viel mit dem Produkt herumspielen können. Bei jeder Neugestaltung eines Autos werden jedoch die Erfahrungen aus früheren Bauten herangezogen, und hinter jedem Gebäude stecken rund tausend Jahre Fundamentaldaten über die Bedeutung von Raum, Licht, Isolierung, Festigkeit usw. Sowohl in den Gebäuden als auch in den Details werden Änderungen vorgenommen und Verbesserungen vorgenommen und in Redesigns für neuere.
Auch Teile werden getestet. Möglicherweise nicht genau im selben Stil wie Software, aber mechanische Teile (Räder, Zünder, Kabel) werden normalerweise gemessen und belastet, um sicherzustellen, dass die Größen korrekt sind, keine Abnormalitäten erkennbar sind usw. Gemessen tippen sie auf Steine, um defekte zu erkennen, sie werden möglicherweise tatsächlich in der einen oder anderen Konfiguration getestet, oder sie zeichnen eine begrenzte Darstellung einer großen Gruppe, um sie wirklich zu testen.
All das können Sie mit TDD umsetzen.
Und in der Tat ist das Testen keine Garantie. Programme stürzen ab, Autos fahren kaputt und Gebäude fangen an, lustige Dinge zu tun, wenn der Wind weht. Aber ... "Sicherheit" ist keine boolesche Frage. Selbst wenn Sie nicht immer alles einbeziehen können, ist es besser, 99% der Eventualitäten abzudecken, als nur 50%. Nicht testen und dann herausfinden, dass sich der Stahl nicht gut gesetzt hat und brüchig ist und beim ersten Hammerschlag bricht, wenn Sie gerade Ihre Hauptstruktur aufbauen, ist eine reine Geldverschwendung. Dass es noch andere Bedenken gibt, die dem Gebäude schaden könnten, macht es nicht weniger dumm, wenn ein leicht vermeidbarer Fehler Ihr Design zum Erliegen bringt.
In Bezug auf die TDD-Praxis ist dies eine Frage des Ausgleichs. Die Kosten für die einfache Ausführung (z. B. nicht testen und dann die Teile später abholen) im Vergleich zu den Kosten für die andere Ausführung. Es ist immer ein Gleichgewicht. Denken Sie jedoch nicht, dass in anderen Entwurfsprozessen keine Tests und TDD vorhanden sind.
quelle
IMO, die meisten Erfolgsgeschichten für TDD sind gefälscht und nur für Marketingzwecke gedacht. Es kann sehr wenig Erfolg damit geben, aber nur für kleine Anwendungen. Ich arbeite an einer großen Silverlight-Anwendung, in der TDD-Prinzipien verwendet werden. Die Anwendung hat Hunderte von Tests, ist aber immer noch nicht stabil. Einige Teile der Anwendung können aufgrund der komplexen Benutzerinteraktionen nicht getestet werden. Resultierende Tests mit vielen Verspottungen und schwer zu verstehendem Code.
Als wir TDD ausprobiert haben, scheint alles gut zu sein. Ich konnte viele Tests schreiben und die Teile, die für einen Komponententest schwierig sind, verhöhnen. Sobald Sie eine ausreichende Menge an Code haben und eine Schnittstellenänderung erforderlich ist, sind Sie fertig. Viele Tests müssen repariert werden und Sie werden mehr Tests als die eigentliche Änderung im Code neu schreiben.
Peter Norvig erklärt seine Sicht auf TDD im Coders At Work-Buch.
quelle
well, you haven't done TDD right!
Test Driven Design funktioniert für mich aus folgenden Gründen:
Es ist eine ausführbare Form der Spezifikation.
Dies bedeutet, dass Sie aus den Testfällen sehen können:
Sie schreiben die Ansicht zuerst von außen.
Häufig wird Code so geschrieben, dass Sie zuerst das Problem lösen und dann überlegen, wie der soeben geschriebene Code aufgerufen werden soll. Dies führt häufig zu einer umständlichen Benutzeroberfläche, da es häufig einfacher ist, "nur ein Flag hinzuzufügen" usw. Wenn Sie sich überlegen, dass "DAS müssen wir tun, damit die Testfälle so aussehen", drehen Sie dies um. Dies ergibt eine bessere Modularität, da der Code gemäß der aufrufenden Schnittstelle geschrieben wird und nicht umgekehrt.
Dies führt in der Regel zu einem saubereren Code, der weniger erklärende Dokumentation erfordert.
Sie werden schneller erledigt
Da Sie die Spezifikation für ausführbare Formulare haben, sind Sie fertig, wenn die vollständige Testsuite bestanden wurde. Sie können weitere Tests hinzufügen, wenn Sie die Dinge detaillierter klären, aber als Grundprinzip haben Sie einen sehr klaren und sichtbaren Indikator für den Fortschritt und wenn Sie fertig sind.
Dies bedeutet, dass Sie erkennen können, wann Arbeit erforderlich ist oder nicht (hilft es, einen Test zu bestehen), und am Ende weniger tun müssen.
Für diejenigen, die darüber nachdenken, ist es möglicherweise hilfreich, TDD für Ihre nächste Bibliotheksroutine zu verwenden. Richten Sie langsam eine ausführbare Spezifikation ein und lassen Sie den Code die Tests bestehen. Anschließend steht die ausführbare Spezifikation allen Benutzern zur Verfügung, die sehen möchten, wie die Bibliothek aufgerufen wird.
Kürzlich durchgeführte Studie
"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 verzeichneten die Teams einen Anstieg von 15 bis 35% erste Entwicklungszeit nach Einführung von TDD. " ~ Ergebnisse und Erfahrungen von 4 Industrieteams
quelle
Beim Erstellen von Software handelt es sich nicht um das Schreiben des Codes. Kein Softwareprojekt sollte zuerst ohne einen Plan für einen breiten Anwendungsbereich gestartet werden. Genau wie ein Projekt, bei dem zwei Ufer eines Flusses überbrückt werden sollen, braucht man einen solchen Plan zuerst.
Der TDD-Ansatz bezieht sich (meistens) auf Unit-Tests - zumindest neigen die Leute dazu, darüber nachzudenken -, bei denen die einfachsten Teile des Software-Codes erstellt werden. Wenn alle Funktionen und Verhaltensweisen bereits definiert wurden und wir tatsächlich wissen, was wir erreichen möchten.
In der Tragwerksplanung sieht es ungefähr so aus:
Um zu testen, ob die Software als Ganzes funktioniert, entwickeln wir andere Arten von Tests wie Usability-Tests, Integrationstests und Abnahmetests. Auch diese sollten definiert werden, bevor die eigentliche Arbeit am Schreiben des Codes beginnt, und werden ausgeführt, nachdem die Komponententests grün sind.
Siehe V-Modell: http://en.wikipedia.org/wiki/V-Model_%28software_development%29
Mal sehen, wie es für eine Brücke funktionieren würde:
Eine lokale Regierung sagt zu einer Brückenbaufirma: "Wir brauchen eine Brücke, um diese beiden Punkte zu verbinden. Die Brücke muss in der Lage sein, n Verkehr pro Stunde zuzulassen und für den 21. Dezember 2012 fertig zu sein" - das ist eine Definition von Akzeptanztest: Das Unternehmen erhält keinen vollen Geldbetrag (oder kein Geld), wenn es diesen Test nicht besteht.
Die Geschäftsführung entscheidet über den Projektablauf. Sie stellen Arbeitsteams auf und setzen Ziele für jedes Team. Wenn die Teams diese Ziele nicht erreichen, wird die Brücke nicht rechtzeitig gebaut. Allerdings gibt es hier ein gewisses Maß an Flexibilität. Wenn eines der Teams Probleme hat, kann das Unternehmen dies ausgleichen, indem es die Anforderungen ändert, Subunternehmer wechselt, mehr Mitarbeiter einstellt usw., sodass das gesamte Projekt weiterhin das unter Punkt 1 festgelegte Ziel erreicht.
In einem Team, das für das Entwerfen bestimmter Brückenkomponenten verantwortlich ist, sieht es so aus, wie im obigen Beispiel. Manchmal liegt die Lösung auf der Hand, weil wir über ein umfangreiches Wissen in Bezug auf das Bauen von Brücken verfügen (es ist, als würde man eine gut getestete Bibliothek in der Softwareentwicklung verwenden - man geht einfach davon aus, dass sie wie angekündigt funktioniert). Manchmal müssen Sie mehrere Designs erstellen und testen, um das beste auszuwählen. Die Kriterien, nach denen die Komponente getestet wird, sind jedoch im Voraus bekannt.
quelle
In meinen Gedanken funktioniert TDD weil
Speziell auf die Punkte, die Sie erhöhen
quelle
TL; DR
Programmieren ist immer noch eine Designaktivität, es ist keine Konstruktion. Durch das Schreiben von Unit-Tests wird nur bestätigt, dass der Code das tut, was er tut, und nicht, dass er etwas Nützliches tut. Testfehler sind der wahre Wert, da Sie Fehler frühzeitig erkennen können.
Code ist Design
In Kapitel 7 von PPP spricht "Onkel Bob" direkt über dieses Problem. Sehr früh in diesem Kapitel verweist er auf einen ausgezeichneten Artikel von Jack Reeves, in dem er vorschlägt, dass Code Design ist (der Link führt zu einer Seite, auf der alle drei Artikel zu diesem Thema zusammengefasst sind).
Das Interessante an diesem Argument ist, dass er darauf hinweist, dass die Erstellung von Software im Gegensatz zu anderen Ingenieurdisziplinen, in denen das Bauen eine sehr teure Aktivität ist, relativ kostenlos ist (Hit Compile in Ihrer IDE und Sie haben Ihre erstellte Software). Wenn Sie das Schreiben von Code als Entwurfsaktivität statt als Konstruktionsaktivität betrachten, ist der Rot-Grün-Refaktor-Zyklus im Grunde eine Übung im Entwurf. Ihr Design entwickelt sich, wenn Sie Tests schreiben, den Code, um diese zu erfüllen, und den neuen Code umzugestalten, um ihn in das vorhandene System zu integrieren.
TDD als Spezifikation
Die Unit-Tests, die Sie für TDD schreiben, sind eine direkte Übersetzung der Spezifikation, so wie Sie sie verstehen. Wenn Sie Code schreiben, der Ihre Spezifikation nur minimal erfüllt (Ihre Tests werden grün), ist der gesamte von Ihnen geschriebene Code für einen bestimmten Zweck da. Ob dieser Zweck erfüllt wurde oder nicht, wird durch einen wiederholbaren Test bestätigt.
Schreiben Sie Tests zur Funktionalität
Ein häufiger Fehler beim Komponententest tritt auf, wenn Sie die Tests nach dem Code schreiben und am Ende testen, ob der Code das tut, was er tut. Mit anderen Worten, Sie werden Tests wie diese sehen
Obwohl ich denke, dass dieser Code nützlich sein könnte (stellen Sie sicher, dass jemand mit einer einfachen Eigenschaft nichts Obszönes angestellt hat). Es dient nicht zur Validierung einer Spezifikation. Und wie Sie sagten, bringt Sie das Schreiben solcher Tests nur so weit.
Während Grün gut ist, liegt der Wert in Rot. Ich hatte meinen ersten wahren "Aha" -Moment in TDD, als ich einen unerwarteten Testfehler bekam. Ich hatte eine Reihe von Tests, die ich für ein Framework hatte, das ich baute. Ich habe eine neue Funktion hinzugefügt und einen Test dafür geschrieben. Dann habe ich den Code geschrieben, um den Test zu bestehen. Kompilieren, testen ... hat beim neuen Test ein Grün bekommen. Aber auch bei einem anderen Test, von dem ich nicht erwartet hatte, dass er rot wird, wurde er rot.
Wenn ich mir das Scheitern anschaue, atme ich erleichtert auf, weil ich bezweifle, dass ich diesen Fehler längere Zeit hätte finden können, wenn ich diesen Test nicht durchgeführt hätte. Und es war ein sehr böser Fehler zu haben. Glücklicherweise hatte ich den Test und er sagte mir genau, was ich tun musste, um den Fehler zu beheben. Ohne den Test hätte ich mein System weiter aufgebaut (mit dem Fehler, der andere Module infiziert, die von diesem Code abhängen), und bis der Fehler entdeckt wurde, wäre es eine Hauptaufgabe gewesen, ihn richtig zu beheben.
Der wahre Vorteil von TDD besteht darin, dass wir Änderungen mit rücksichtsloser Zurückhaltung vornehmen können. Es ist wie ein Sicherheitsnetz für die Programmierung. Überlegen Sie, was passieren würde, wenn ein Trapezkünstler einen Fehler macht und fällt. Mit dem Netz ist es ein peinlicher Fehler. Ohne ist es eine Tragödie. In gleicher Hinsicht erspart Ihnen TDD, Fehler auf den Knochen in Katastrophen umzuwandeln, die zum Tod von Projekten führen.
quelle
Sie werden niemanden finden, der Test Driven Development oder Test Driven Design befürwortet (sie sind anders), das besagt, dass Tests Anwendungen beweisen. Nennen wir das also einfach einen Strohmann und fertig.
Sie werden niemanden finden, der TDD nicht mag oder von ihm nicht beeindruckt ist. Tests sind eine Verschwendung von Zeit und Mühe. Tests beweisen zwar keine Anwendungen, sind jedoch bei der Fehlersuche sehr hilfreich.
Mit diesen beiden Worten unternimmt keine der beiden Seiten etwas anderes, um tatsächlich Tests an der Software durchzuführen. Beide testen. Beide verlassen sich auf Tests, um so viele Fehler wie möglich zu finden, und beide verwenden Tests, um zu überprüfen, ob ein Softwareprogramm funktioniert und zu dem Zeitpunkt entdeckt werden kann. Niemand mit einer halben Ahnung verkauft Software ohne zu testen und niemand mit einer halben Ahnung erwartet, dass das Testen den Code, den sie verkaufen, völlig fehlerfrei macht.
Der Unterschied zwischen TDD und Nicht-TDD besteht also nicht darin, dass Tests durchgeführt werden. Der Unterschied besteht darin, wann die Tests geschrieben werden. In TDD werden Tests VOR der Software geschrieben. Bei Nicht-TDD-Tests erfolgt die Erstellung nach oder in Abstimmung mit der Software.
Das Problem, das ich in Bezug auf Letzteres gesehen habe, ist, dass das Testen darauf abzielt, dass die Software mehr als das gewünschte Ergebnis oder die gewünschte Spezifikation geschrieben wird. Selbst wenn das Testteam vom Entwicklungsteam getrennt ist, tendiert das Testteam dazu, sich die Software anzusehen, damit zu spielen und Tests zu schreiben, die darauf abzielen.
Eine Sache, die von denjenigen, die den Projekterfolg studieren, immer wieder bemerkt wurde, ist, wie oft ein Kunde das darlegt, was er will, die Entwickler davonlaufen und etwas schreiben und wenn sie zu dem Kunden zurückkehren, sagen sie "erledigt". Es stellt sich heraus, dass es absolut NICHT das ist, wonach der Kunde gefragt hat. "Aber es besteht alle Tests ..."
Das Ziel von TDD ist es, dieses "Zirkelargument" zu durchbrechen und die Grundlage für die Tests zu schaffen, mit denen die Software getestet wird, die nicht die Software selbst ist. Die Tests sind so geschrieben, dass sie auf das vom "Kunden" gewünschte Verhalten abzielen. Die Software wird dann geschrieben, um diese Tests zu bestehen.
TDD ist Teil der Lösung, die dieses Problem lösen soll. Es ist nicht der einzige Schritt, den Sie machen. Sie müssen außerdem sicherstellen, dass mehr und häufiger Kundenfeedback eingeht.
Nach meiner Erfahrung ist es jedoch sehr schwierig, TDD erfolgreich umzusetzen. Es ist schwierig, Tests zu schreiben, bevor es ein Produkt gibt, da für viele automatisierte Tests etwas zum Spielen erforderlich ist, damit die Automatisierungssoftware richtig funktioniert. Es ist auch schwierig, Entwickler, die nicht an Unit-Tests gewöhnt sind, dazu zu bewegen. Immer wieder habe ich die Leute in meinem Team angewiesen, die Tests ZUERST zu schreiben. Ich habe noch nie einen dazu gebracht. Letztendlich haben Zeitdruck und Politik alle Anstrengungen zunichte gemacht, so dass wir nicht einmal mehr Unit-Tests durchführen. Dies führte natürlich unweigerlich dazu, dass das Design versehentlich und streng gekoppelt wurde, so dass es jetzt unerschwinglich und kostspielig wäre, es zu implementieren, selbst wenn wir es wollten. Dies zu vermeiden, ist es, was TDD letztendlich für Entwickler bereitstellt.
quelle
Design zuerst
TDD ist keine Entschuldigung, um Design zu überspringen. Ich habe viele Sprünge im "agilen" Zug gesehen, weil sie mit dem Codieren sofort beginnen konnten. Echte Agilität bringt Sie viel schneller zur statistischen Codierung als die bewährten Methoden der (anderen Fach-) Technik, die den Wasserfallprozess inspiriert haben.
Aber früh testen
Wenn man sagt, dass die Tests das Design vorantreiben, bedeutet dies einfach, dass man Tests sehr früh in der Designphase anwenden kann, lange bevor sie abgeschlossen sind. Wenn Sie diese Tests durchführen, wird Ihr Design stark beeinflusst, indem Sie die Grauzonen herausfordern und gegen die reale Welt antreten, lange bevor das Produkt fertiggestellt ist. Sie müssen häufig zum Design zurückkehren und es anpassen, um dies zu berücksichtigen.
Test und Design ... ein und dasselbe
Meiner Meinung nach ist es bei TDD einfach so, dass der Test ein wesentlicher Bestandteil des Designs ist, anstatt dass am Ende etwas getan wird, um ihn zu validieren. Wenn Sie TDD immer häufiger einsetzen, werden Sie sich immer mehr darüber im Klaren, wie Sie Ihr System beim Entwerfen zerstören oder zerstören können. Persönlich mache ich meine Tests nicht immer zuerst. Sicher, ich mache die offensichtlichen (Einheiten-) Tests an einer Schnittstelle, aber der eigentliche Gewinn ergibt sich aus den Integrations- und Spezifikationstests, die ich erstelle, wenn ich mir überlege, wie dieses Design auf neue und kreative Weise funktionieren kann. Sobald mir eine Möglichkeit einfällt, programmiere ich einen Test und sehe, was passiert. Manchmal kann ich mit der Konsequenz leben, in diesem Fall verschiebe ich den Test in ein separates Projekt, das nicht Teil des Haupt-Builds ist (da es weiterhin fehlschlagen wird).
Wer fährt dann die Show?
In TDD bedeutet das hier Fahren einfach, dass Ihre Tests Ihr Design so stark beeinflussen, dass man das Gefühl hat, dass sie es tatsächlich fahren. Wie auch immer man damit aufhört und hier verstehe ich Ihre Bedenken, es ist ein bisschen beängstigend ... wer treibt die Show an?
SIE fahren, nicht die Tests. Die Tests sind da, damit Sie auf Ihrem Weg ein gutes Maß an Vertrauen in das, was Sie geschaffen haben, gewinnen und so besser wissen können, dass es auf einem soliden Grund ruht.
fest, solange die Tests fest sind
Genau , daher der im TDD gefahrene. Es ist nicht so sehr, dass die Tests das Ganze vorantreiben, aber sie werden einen so tiefen Einfluss darauf haben, wie Sie Dinge tun, wie Sie Ihr System entwerfen und denken, dass Sie einen großen Teil Ihres Denkprozesses an Tests delegieren und im Gegenzug Sie werden einen tiefen Einfluss auf Ihr Design haben.
ja aber wenn ich das mit meiner brücke mache th ....
genau dort aufhören ... Software-Engineering unterscheidet sich SEHR von allen anderen Engineering-Praktiken auf dem Markt. Tatsächlich hat Software-Engineering viel mehr mit Literatur zu tun. Man kann ein fertiges Buch nehmen, 4 Kapitel daraus rippen und zwei neue Kapitel schreiben, um sie zu ersetzen, und sie wieder in das Buch stecken, und man hat immer noch ein gutes Buch. Mit guten Tests und Software können Sie jeden Teil Ihres Systems rippen und durch einen anderen ersetzen, und die Kosten dafür sind nicht viel höher als die, die es ursprünglich erstellt hat. Wenn Sie Ihre Tests durchgeführt haben und es ihnen erlaubt haben, Ihr Design ausreichend zu beeinflussen, kann dies sehr wohl billiger sein als die erstmalige Erstellung, da Sie sicher sind, dass dieser Ersatz nicht die Anforderungen der Tests erfüllt.
Wenn es sooo gut ist, warum funktioniert es nicht immer?
Weil das Testen eine SEHR andere Denkweise erfordert als das Bauen. Nicht jeder ist in der Lage, zurückzuschalten, und tatsächlich werden einige Menschen nicht in der Lage sein, geeignete Tests zu erstellen, nur weil sie sich nicht dazu entschließen können, ihre Schöpfung zu zerstören. Dies führt zu Projekten mit zu wenigen Tests oder Tests, die gerade ausreichen, um eine Zielmetrik zu erreichen (man denke an die Codeabdeckung). Sie werden gerne Pfad- und Ausnahmetests durchführen, aber die Eckfälle und Randbedingungen vergessen.
Andere werden sich nur auf Tests verlassen, die teilweise oder vollständig auf das Design verzichten. Jedes Mitglied tut seine Sache und integriert sich dann miteinander. Design ist zuallererst ein Kommunikationsinstrument. Wir setzen alles daran, um zu sagen, dass ich hier sein werde. Skizzen, die besagen, dass hier die Türen und Fenster sein werden. Ohne dies ist Ihre Software zum Scheitern verurteilt, unabhängig davon, wie viele Tests Sie in das Ding stecken. Integration und Zusammenführung werden immer schmerzhaft sein und es wird ihnen an Tests auf höchstem Abstraktionsniveau mangeln.
Für diese Teams ist TDD möglicherweise nicht der richtige Weg.
quelle
Mit TDD schreiben Sie in der Regel keinen Code, der nicht einfach oder schnell zu testen ist. Dies mag klein erscheinen, kann sich jedoch tiefgreifend auf ein Projekt auswirken, da es sich darauf auswirkt, wie einfach es ist, Fehler mit Tests umzugestalten, zu testen, zu reproduzieren und Korrekturen zu überprüfen.
Es ist für einen neuen Entwickler im Projekt auch einfacher, auf dem Laufenden zu bleiben, wenn Sie Code mit besseren Faktoren haben, der durch Tests unterstützt wird.
quelle
Ich habe viel darüber nachgedacht, obwohl ich selbst nicht so viel TDD praktiziere. Es scheint eine (starke?) Positive Korrelation zwischen der Codequalität und der folgenden TDD zu geben.
1) Meine erste Annahme ist, dass dies (in erster Linie) nicht darauf zurückzuführen ist, dass TDD dem Code (als solchem) "bessere Qualität" hinzufügt. TDD hilft eher dabei, die schlimmsten Teile und Gewohnheiten auszumerzen und somit indirekt die Qualität zu erhöhen.
Ich würde sogar befürworten, dass es nicht der Test selbst ist - es ist der Prozess , diese Tests zu schreiben . Es ist schwierig, Tests für einen fehlerhaften Code zu schreiben und umgekehrt. Und wenn Sie dies beim Programmieren im Hinterkopf behalten, werden viele fehlerhafte Codes eliminiert.
2) Eine andere Sichtweise (dies wird philosophisch) folgt den mentalen Gewohnheiten des Meisters. Man lernt nicht, ein Meister zu werden, indem man seinen "äußeren Gewohnheiten" folgt (ein langer Bart ist gut), man muss seine inneren Denkweisen lernen, und das ist schwer. Und irgendwie können (Anfänger-) Programmierer TDD folgen und ihre Denkweise näher an die des Meisters anpassen.
quelle
Sie scheinen ein Missverständnis über Refactoring und TDD zu haben.
Daher können Sie Code erst dann umgestalten , wenn er erfolgreich ist.
Und bei TDD, insbesondere beim Unit-Testen (was ich als Kernverbesserung betrachte, da andere Tests für mich eher plausibel erscheinen), geht es nicht darum, eine Komponente neu zu entwerfen, bis sie funktioniert. Es geht darum, eine Komponente zu entwerfen und an der Implementierung zu arbeiten, bis die Komponente wie geplant funktioniert.
Es ist auch wichtig zu verstehen, dass es beim Unit- Testen um das Testen von Units geht . Aufgrund der Tendenz, immer viele Dinge von Grund auf neu zu schreiben, ist es wichtig, solche Einheiten zu testen. Ein Bauingenieur kennt bereits die Spezifikationen der von ihm verwendeten Einheiten (die verschiedenen Materialien) und kann erwarten, dass sie funktionieren. Dies sind zwei Dinge, die für Software-Ingenieure häufig nicht zutreffen, und es ist sehr pro-technisch, die Einheiten vor der Verwendung zu testen, da dabei getestete, hochwertige Komponenten verwendet werden.
Wenn ein Bauingenieur die Idee hätte, ein neues Fasergewebe für die Herstellung eines Daches zur Abdeckung eines Stadions zu verwenden, würde man von ihm erwarten, dass er es als Einheit testet, dh die erforderlichen Spezifikationen definiert (z. B. Gewicht, Durchlässigkeit, Stabilität usw.) und danach testen und verfeinern, bis es ihnen entspricht.
Deshalb funktioniert TDD. Denn wenn Sie Software aus getesteten Einheiten erstellen, ist die Wahrscheinlichkeit groß, dass sie funktioniert, wenn Sie sie zusammenstecken, und wenn dies nicht der Fall ist, können Sie davon ausgehen, dass das Problem in Ihrem Klebercode enthalten ist, vorausgesetzt, dass Ihre Tests eine gute Abdeckung aufweisen.
Bearbeiten:
Refactoring bedeutet: keine Änderung der Funktionalität. Beim Unit-Test muss sichergestellt werden, dass das Refactoring den Code nicht beschädigt. TDD soll also sicherstellen, dass Refactoring keine Nebenwirkungen hat.
Die Granularität ist kein Gegenstand der Perspektive, denn wie gesagt, Unit-Tests sind Testeinheiten und keine Systeme, bei denen die Granularität genau definiert ist.
TDD fördert gute Architektur. Es erfordert, dass Sie Spezifikationen für alle Ihre Einheiten definieren und implementieren, sodass Sie gezwungen sind, diese vor der Implementierung zu entwerfen, was ganz im Gegenteil zu Ihrer Vermutung ist. TDD schreibt die Erstellung von Einheiten vor, die einzeln getestet und somit vollständig entkoppelt werden können.
TDD bedeutet nicht, dass ich einen Softwaretest mit Spaghetti-Code mache und die Nudeln rühre, bis sie verstrichen sind.
Im Gegensatz zum Tiefbau entwickelt sich im Software-Engineering ein Projekt in der Regel ständig weiter. Im Tiefbau müssen Sie in Position A eine Brücke bauen, die x Tonnen tragen kann und breit genug für n Fahrzeuge pro Stunde ist.
In der Softwareentwicklung kann der Kunde grundsätzlich zu jedem Zeitpunkt (möglicherweise nach Fertigstellung) entscheiden, ob er eine Brücke mit Doppeldeck wünscht und ob er möchte, dass diese mit der nächsten Autobahn verbunden wird, und dass er möchte, dass sie eine Hebebrücke ist, weil sein Unternehmen vor kurzem begann Segelschiffe zu verwenden.
Software-Ingenieure haben die Aufgabe , das Design zu ändern. Nicht weil ihre Entwürfe fehlerhaft sind, sondern weil das der Modus operandi ist. Wenn die Software ausgereift ist, kann sie auf hoher Ebene neu gestaltet werden, ohne dass alle Komponenten auf niedriger Ebene neu geschrieben werden müssen.
Bei TDD geht es darum, Software mit individuell getesteten, stark entkoppelten Komponenten zu erstellen. Gut ausgeführt, wird es Ihnen helfen, schneller und sicherer auf geänderte Anforderungen zu reagieren als ohne.
TDD stellt zusätzliche Anforderungen an den Entwicklungsprozess, verbietet jedoch keine anderen Methoden zur Qualitätssicherung. Zugegeben, TDD bietet nicht die gleiche Sicherheit wie die formale Verifizierung. Andererseits ist die formale Verifizierung äußerst kostenintensiv und auf Systemebene nicht anwendbar. Und trotzdem könnten Sie beide kombinieren, wenn Sie wollten.
TDD umfasst auch andere Tests als Komponententests, die auf Systemebene durchgeführt werden. Ich finde diese einfach zu erklären, aber schwierig auszuführen und schwer zu messen. Auch sind sie durchaus plausibel. Obwohl ich ihre Notwendigkeit absolut sehe, schätze ich sie nicht wirklich als Ideen.
Am Ende löst kein Tool ein Problem. Werkzeuge erleichtern nur das Lösen eines Problems. Sie können sich fragen: Wie hilft mir ein Meißel bei großartiger Architektur? Wenn Sie gerade Wände bauen möchten, sind gerade Ziegel hilfreich. Und ja, selbstverständlich, wenn Sie einem Idioten dieses Werkzeug geben, wird er es wahrscheinlich irgendwann durch den Fuß schlagen, aber das ist nicht die Schuld des Meißels, so sehr es auch kein Fehler von TDD ist, dass es Anfängern falsche Sicherheit gibt. die schreiben keine guten tests.
Unterm Strich kann man also sagen, dass TDD viel besser funktioniert als kein TDD.
quelle
Ich mag es nicht, wenn Sie sagen: "Der Test bestimmt die Anforderungen, nicht der Benutzer." Ich denke, Sie erwägen nur Unit-Tests in TDD, während es auch Integrationstests abdeckt.
Schreiben Sie neben dem Testen der Bibliotheken, die die Basis der Software bilden, auch die Tests, die die Interaktionen Ihrer Benutzer mit der Software / Website / was auch immer abdecken. Diese kommen direkt von den Benutzern, und Bibliotheken wie cucumber (http://cukes.info) können Ihre Benutzer sogar die Tests selbst in natürlicher Sprache schreiben lassen.
TDD fördert auch die Flexibilität im Code - wenn Sie die Architektur von etwas für immer entwerfen, wird es unglaublich schwierig sein, diese Änderungen später vorzunehmen, falls erforderlich. Beginnen Sie mit dem Schreiben einiger Tests und schreiben Sie dann einen kleinen Code, der diese Tests besteht. Fügen Sie mehr Tests hinzu, fügen Sie mehr Code hinzu. Wenn Sie den Code radikal ändern müssen, bleiben Ihre Tests bestehen.
Und im Gegensatz zu Brücken und Autos kann eine einzelne Software im Laufe ihrer Lebensdauer enorme Änderungen erfahren, und komplexe Umbauten ohne vorherige Testerstellung sind nur eine Frage der Mühe.
quelle
Ich denke, Sie nähern sich dem ersten Punkt aus dem falschen Winkel.
Aus theoretischer Sicht beweisen wir, dass etwas funktioniert, indem wir es mit Fehlerpunkten vergleichen. Das ist die angewandte Methode. Es gibt viele andere Möglichkeiten, um zu beweisen, dass etwas funktioniert, aber TDD hat sich aufgrund der Einfachheit seines bitweisen Ansatzes etabliert: Wenn es nicht kaputt geht, funktioniert es.
In der Praxis bedeutet dies ausgesprochen: Wir können jetzt mit dem nächsten Schritt fortfahren (nachdem wir TDD erfolgreich angewendet haben, um alle Prädikate zu erfüllen). Wenn Sie sich aus dieser Perspektive TDD nähern, dann geht es nicht darum, Tests + Refactor bis zum Bestehen zu schreiben, sondern darum , dies abgeschlossen zu haben. Ich konzentriere mich jetzt voll und ganz auf das nächste Feature als das Wichtigste .
Überlegen Sie, wie dies für den Tiefbau gilt. Wir bauen ein Stadion, in dem 150000 Zuschauer Platz haben. Nachdem wir bewiesen haben, dass die strukturelle Integrität des Stadions einwandfrei ist, haben wir zuerst die Sicherheit befriedigt . Wir können uns jetzt auf andere Themen konzentrieren, die sofort wichtig werden, wie z. B. Toiletten, Essensstände, Sitzgelegenheiten usw., um die Erfahrung des Publikums angenehmer zu gestalten. Dies ist eine übermäßige Vereinfachung, da TDD noch viel mehr zu bieten hat. Der springende Punkt ist jedoch, dass Sie nicht das bestmögliche Benutzererlebnis erzielen, wenn Sie sich auf neue und aufregende Funktionen konzentrieren und gleichzeitig die Integrität wahren. Sie bekommen es in beiden Fällen zur Hälfte. Ich meine, wie können Sie genau wissen, wieviele Toiletten und wo sollten Sie für 150000 Menschen platzieren? Ich habe in meinem eigenen Leben selten gesehen, wie Stadien zusammenbrachen, aber ich musste in der Halbzeit so oft in der Schlange stehen. Das heißt, das Toilettenproblem ist wohl komplexer, und wenn die Ingenieure weniger Zeit für die Sicherheit aufwenden können, sind sie möglicherweise in der Lage, das Toilettenproblem zu lösen.
Ihr zweiter Punkt ist irrelevant, weil wir uns bereits darauf geeinigt haben, dass Absolutes ein dummes Unterfangen ist und weil Hank Moody sagt, dass sie nicht existieren (aber ich kann keinen Hinweis dafür finden).
quelle
TDD in der Softwareentwicklung ist eine bewährte Methode, ebenso wie die Fehlerbehandlung in Anwendungen eine bewährte Methode sowie die Protokollierung und Diagnose (obwohl dies Teil der Fehlerbehandlung ist).
TDD darf nicht als Werkzeug verwendet werden, um die Softwareentwicklung auf Trial & Error-Codierung zu reduzieren. Dennoch starren die meisten Programmierer auf Laufzeitprotokolle, beobachten Ausnahmen im Debugger oder verwenden andere Anzeichen für Fehler / Erfolg während ihrer Entwicklungsphase, die aus dem Codieren / Kompilieren / Ausführen der App besteht - den ganzen Tag lang.
TDD ist nur eine Möglichkeit, diese Schritte zu formalisieren und zu automatisieren, um Sie als Entwickler produktiver zu machen.
1) Sie können Softwareentwicklung nicht mit Brückenkonstruktion vergleichen, die Flexibilität bei der Brückenkonstruktion entspricht in keiner Weise der Entwicklung eines Softwareprogramms. Das Erstellen der Brücke ist so, als würde man immer wieder dasselbe Programm in eine verlustbehaftete Maschine schreiben. Bridges können nicht wie Software dupliziert und wiederverwendet werden. Jede Brücke ist ein Unikat und muss hergestellt werden. Das gilt auch für Autos und andere Designs.
Das Schwierigste in der Softwareentwicklung ist die Reproduktion von Fehlern. Wenn eine Brücke ausfällt, ist es normalerweise sehr einfach zu bestimmen, was schief gelaufen ist, und theoretisch ist es einfach, den Fehler zu reproduzieren. Wenn ein Computerprogramm ausfällt, kann es sich um eine komplexe Ereigniskette handeln, die das System in einen fehlerhaften Zustand versetzt hat, und es kann sehr schwierig sein, festzustellen, wo der Fehler liegt. TDD- und Unit-Test erleichtern das Testen der Robustheit von Softwarekomponenten, Bibliotheken und Algorithmen.
2) Die Verwendung schwacher Komponententests und flacher Testfälle, die das System nicht belasten, um ein falsches Gefühl des Vertrauens aufzubauen, ist nur eine schlechte Praxis. Das Ignorieren der architektonischen Qualität eines Systems und das Erfüllen der Tests sind natürlich genauso schlecht. Aber auf dem Bauplatz für einen Wolkenkratzer oder eine Brücke zu schummeln, um Material zu sparen und den Bauplänen nicht zu folgen, ist genauso schlimm und passiert die ganze Zeit ...
quelle
Wenn Sie akzeptieren, dass die Kosten für die Fehlerbehebung umso geringer sind, je früher Fehler gefunden werden, dann macht sich TDD allein schon dadurch bezahlt.
quelle
Bei TDD geht es nicht wirklich um Tests. Und es ist sicherlich kein Ersatz für gute Tests. Sie erhalten ein durchdachtes Design , das für den Verbraucher leicht zu konsumieren und später einfach zu warten und zu überarbeiten ist. Diese Dinge wiederum führen zu weniger Fehlern und einem besseren, anpassungsfähigeren Softwaredesign. TDD hilft Ihnen auch dabei, Ihre Annahmen zu überdenken und zu dokumentieren, wobei Sie häufig feststellen, dass einige davon falsch waren. Sie finden dies sehr früh im Prozess heraus.
Und als netter Nebeneffekt haben Sie eine große Reihe von Tests, die Sie ausführen können, um sicherzustellen, dass ein Refactoring das Verhalten (Ein- und Ausgaben) Ihrer Software nicht verändert.
quelle
Ich gebe dir eine kurze Antwort. Normalerweise wird TDD genauso falsch betrachtet wie Unit-Tests. Ich habe Unit-Tests erst kürzlich verstanden, nachdem ich mir ein gutes Tech-Talk-Video angesehen hatte. Grundsätzlich sagt TDD nur, dass Sie die folgenden Dinge ARBEITEN möchten. Sie MÜSSEN umgesetzt werden. Dann gestalten Sie den Rest der Software wie gewohnt.
Es ähnelt dem Schreiben von Use Cases für eine Bibliothek vor dem Entwerfen der Bibliothek. Es sei denn, Sie können den Anwendungsfall in einer Bibliothek ändern und möglicherweise nicht für TDD (ich verwende TDD für das API-Design). Sie werden auch dazu ermutigt, weitere Tests hinzuzufügen und über wilde Inputs / Verwendungen nachzudenken, die der Test möglicherweise erhält. Ich finde es nützlich, wenn Sie Bibliotheken oder APIs schreiben, bei denen Sie wissen müssen, dass Sie etwas kaputt gemacht haben, wenn Sie etwas ändern. In den meisten alltäglichen Programmen stört mich das nicht, denn warum brauche ich einen Testfall für einen Benutzer, der eine Taste drückt, oder wenn ich eine CSV-Liste oder eine Liste mit einem Eintrag pro Zeile akzeptieren möchte ... Das ist eigentlich egal, was ich zulasse Um es zu ändern, sollte ich TDD nicht verwenden.
quelle
Software ist organisch, wenn Tragwerksplanung konkret ist.
Wenn Sie Ihre Brücke bauen, bleibt sie eine Brücke und es ist unwahrscheinlich, dass sie sich innerhalb kurzer Zeit zu etwas anderem entwickelt. Verbesserungen werden über Monate und Jahre vorgenommen, jedoch nicht über Stunden und Tage wie bei Software.
Wenn Sie isoliert testen, gibt es normalerweise zwei Arten von Frameworks, die Sie verwenden können. Eingeschränkter Rahmen und uneingeschränkt. Mit uneingeschränkten Frameworks (in .NET) können Sie unabhängig von den Zugriffsmodifikatoren alles testen und ersetzen. Das heißt, Sie können private und geschützte Komponenten stummschalten und verspotten.
Die meisten Projekte, die ich gesehen habe, verwenden eingeschränkte Frameworks (RhinoMocks, NSubstitute, Moq). Wenn Sie mit diesen Frameworks testen, müssen Sie Ihre Anwendung so gestalten, dass Sie zur Laufzeit Abhängigkeiten einfügen und ersetzen können. Dies impliziert, dass Sie ein lose gekoppeltes Design haben müssen. Locker gekoppeltes Design (wenn es richtig gemacht wird) impliziert eine bessere Trennung von Bedenken, was eine gute Sache ist.
Zusammenfassend kann ich sagen, dass das Denken dahinter darin besteht, dass Ihr Design, wenn es testbar ist, daher lose gekoppelt ist und eine gute Trennung der Bedenken aufweist.
Nebenbei bemerkt, ich habe Anwendungen gesehen, die wirklich testbar, aber aus objektorientierter Designperspektive schlecht geschrieben waren.
quelle
Das tut es nicht.
Klarstellung: Automatisierte Tests sind besser als keine Tests. Ich persönlich halte die meisten Komponententests jedoch für Verschwendung, da sie in der Regel tautologisch sind (dh Dinge, die sich aus dem tatsächlich getesteten Code ergeben) und nicht ohne Weiteres nachgewiesen werden können, dass sie konsistent und nicht redundant sind und alle Grenzfälle abdecken (in denen normalerweise Fehler auftreten) ).
Und das Wichtigste: Gutes Softwaredesign fällt nicht auf magische Weise aus Tests heraus, da es von vielen agilen / TDD-Evangelisten beworben wird. Alle, die etwas anderes behaupten, geben bitte Links zu von Experten geprüften wissenschaftlichen Forschungsergebnissen an, die dies belegen, oder verweisen zumindest auf ein Open-Source-Projekt, bei dem die Vorteile von TDD möglicherweise anhand der bisherigen Codeänderungen untersucht werden können.
quelle