Warum dreht sich bei Agile alles um die testgetriebene Entwicklung (TDD) und nicht um den entwicklungsgetriebenen Test (DDT)?

74

Ich bin neu in der agilen, aber nicht testgetriebenen Entwicklung . Bei meinen Professoren am College drehte sich alles um die Idee von Tests, dann Code, dann Tests. Ich bin mir nicht sicher, warum ich das verstehe. Aus meiner Sicht sind es viele Vorlaufkosten, die sich höchstwahrscheinlich ändern werden, wenn sich Ihr Code weiterentwickelt.

So stelle ich mir TDD vor und warum es mich verwirrt. Wenn ich als TDD-Bauunternehmer ein Haus bauen würde.

  1. Geben Sie mir alle Ihre Angaben (Geschichten).

  2. Lassen Sie sich von den Spezifikationen genehmigen.

  3. Teilen Sie alle Spezifikationen in Inspektionen auf, von denen ich glaube, dass sie erforderlich sind (siehe in die Zukunft).

  4. Rufen Sie einen Inspektor an, um sich diese Punkte anzuschauen, und teilen Sie mir mit, dass ich die Inspektion nicht bestanden habe (Danke).

  5. Baue das Haus.

  6. Rufen Sie den Inspektor täglich zurück (vorbei an 2/100).

  7. Oh, schieß, es gab ein Problem mit meinem Verständnis und jetzt muss ich 9 weitere Inspektionen hinzufügen und 27 davon ändern.

  8. Rufen Sie den Inspektor an, der 1/109 passiert.

  9. Verdammt. Warum gefällt der Inspektor nicht ... oh, ich habe diesen Methodennamen aktualisiert ...

  10. Baue noch mehr.

  11. UGGGGHHHH MEHR ÄNDERUNGEN lassen Sie mich den verdammten Inspektor aktualisieren. Oh, ich versage nicht.

  12. Bin ich schon fertig

Okay, das ist vielleicht komisch, aber ich sehe einfach nicht, wie ich alle meine Methoden kennen sollte und wie die Dinge funktionieren, bis mein Code da ist. In 99% der Fälle muss ich zurückgehen und einen Komponententest auf irgendeine Weise aktualisieren und im Laufe der Zeit weitere hinzufügen. Es scheint nur rückwärts.

Was angemessener erscheint, ist DDT oder entwicklungsgetriebenes Testen, was die Community anscheinend so gut wie vergessen hat.

Nach meinem Verständnis würde DDT für ein Haus so aussehen:

  1. Geben Sie mir alle Ihre Angaben (Geschichten).

  2. Holen Sie sich die Genehmigung für die Spezifikationen und brechen Sie sie aus.

  3. Starten Sie eine Einheit (das Fundament).

  4. Machen Sie sich Notizen (Kommentare) zu einer kniffligen Logik.

  5. Am Ende vor Beginn der nächsten Einheit die Inspektion durchführen (Test erstellen).

  6. Beheben Sie alle gefundenen Probleme und überprüfen Sie sie erneut.

  7. Genehmigt, dass dieses Gerät zum nächsten wechselt.

Wenn wir alle ehrlich sind, klingt das nicht menschlicher und konzentriert sich auf Entwickler und Unternehmen? Es scheint, dass Änderungen schneller vorgenommen werden können und ohne dass der Overhead TDD zu erstellen scheint.

Nerdlyist
quelle
60
Die grelle Trennung für mich ist die Idee, dass Sie mehr als 100 fehlerhafte Tests haben können, bevor Sie den Code schreiben, der beginnt, sie zu bestehen. Wie @Telastyn sagt, sollte es nicht mehr als ein paar fehlgeschlagene Tests gleichzeitig geben. "Tests, dann Code, dann Test" bedeutet nicht, dass Sie alle Tests der App schreiben, bevor Sie Code schreiben.
Eric King
33
Metaphern sind ein Gegenmuster! Die Leute werden mehr Zeit damit verbringen, zu erklären, warum Ihre Metapher nicht zum Thema passt, als sich mit Ihrem eigentlichen Anliegen zu befassen. In diesem Fall scheint es Ihre eigentliche Sorge zu sein, dass Sie glauben, alle Tests im Voraus schreiben zu müssen .
JacquesB
21
Nebenbei bemerkt, TDD wird häufig in agilen Projekten verwendet, aber ich denke, es ist wichtig, zwischen agilem Projektmanagement und agilen Entwicklungspraktiken zu unterscheiden. Es gibt keine sehr starke Beziehung zwischen den beiden. Sie können unabhängig von der Projektmethodik die meisten agilen Entwicklungsmethoden anwenden und umgekehrt. Es wird oft vergessen, dass es bei Agilität im Kern wirklich darum geht, Ihren Ansatz nach Bedarf anzupassen, um das beste Ergebnis zu erzielen, und nicht darum, eine Liste der Dinge zu erstellen, die Sie tun müssen. Mit anderen Worten, Agile! = Scrum + TDD.
JimmyJames
35
Der Vergleich der Softwareentwicklung mit dem Bau eines Hauses ist sinnlos. Die Studien wurden durchgeführt. Die Ergebnisse sind in. Die Antwort ist klar. Sie erstellen Software einfach nicht so, wie Sie ein Haus bauen. Das. Zwei. Sind. Anders.
Riwalk
14
Bei Agile dreht sich alles um schnelle Rückkopplungsschleifen, TDD ist nur eine bestimmte Art von Rückkopplungsschleifen
jk.

Antworten:

83

Einer der Vorteile eines TDD-Ansatzes wird nur realisiert, wenn Sie auch Emergent Design ausführen.

In Ihrer ersten Analogie würden Sie also nicht 100 Tests schreiben, da Sie unmöglich wissen werden, wie Ihre Software aussehen wird.

Sie schreiben einen Test. Du machst es. Es schlägt fehl. Sie schreiben die kleinste Codeeinheit, um den Test zu bestehen. Dann führen Sie Ihren Test erneut durch. Es geht vorbei.

Schreiben Sie nun den nächsten Test und wiederholen Sie den obigen Vorgang.

Dies mag zu Beginn wie eine verschwenderische Herangehensweise erscheinen, wenn es offensichtlich ist, was Ihr Code bewirken soll, aber das Tolle an dieser Herangehensweise ist, dass Ihre Testabdeckung immer hoch ist und das Code-Design auf diese Weise sauberer ist.

Als Methode geht es Hand in Hand mit der Paarprogrammierung; Ein Paar schreibt den Test, das nächste schreibt den Code, damit er erfolgreich ist, und schreibt dann den nächsten Test und so weiter.

Ich benutze diesen Ansatz sogar, wenn ich eine neue Klasse schreibe. Der erste Test ist ein Aufruf zum Initiieren des Klassenkonstruktors. Aber ich habe die Klasse noch nicht geschrieben, deshalb schlägt sie fehl. Als nächstes schreibe ich die einfache, leere Klasse, und mein erster Test besteht.

Wenn Sie erst einmal in die Denkweise eingedrungen sind, ist es sehr schwierig, sich nicht darauf einzulassen und die "altmodische" Art und Weise zu kodieren.

Ich würde empfehlen, in einer guten agilen Umgebung zu arbeiten, um dies zu lernen, oder ein paar gute agile Bücher zu lesen (Clean Code und Clean Coder sind beide sehr gut), um dies besser zu verstehen.

Phil Riley
quelle
46
Mit dem Begriff "Emergent Design" können Sie ein Software-Design erweitern, indem Sie Tests bestehen. Das kannst du nicht.
Robert Harvey
28
@nerdlyist: Vergiss aber nicht das Design. Sie müssen noch Software entwerfen. gutes design entsteht nicht nur auf natürliche weise aus einem rot-grün-refaktor. TDD fördert gutes Design, schafft es aber nicht.
Robert Harvey
19
@RobertHarvey, ich bin völlig anderer Meinung als Ihr " Der Begriff" Emergent Design "lässt den Eindruck entstehen, dass Sie ein Software-Design entwickeln können, indem Sie Tests bestehen. Sie können nicht ". Ich kann Ihnen versichern, dass dies auch möglich ist, nachdem ich dies bereits mehrfach getan habe.
David Arno
12
@DavidArno: Beginnen Sie mit einer Anforderungsspezifikation in der Hand? Wie übersetzen Sie diese Spezifikation in eine sinnvolle Architektur? Erfinden Sie es jedes Mal mit Tests neu oder haben Sie frühere architektonische Prinzipien im Hinterkopf? Niemand macht das im Blinden; Es ist überhaupt nichts Magisches daran, Ihre Tests zuerst zu schreiben, außer dass Sie gezwungen sind, Ihren Code testbarer zu machen.
Robert Harvey
45
@DavidArno Ich glaube, Ihr Einwand rührt daher, dass Sie sich als erfahrener Entwickler / Architekt nicht genug Anerkennung zollen. Da Sie bereits intuitiv wissen, wie Modul X aussieht , werden Ihre Tests Ihre Entwicklung in eine gute Richtung lenken. Ein unerfahrener Entwickler, der vor dem Schreiben der Tests nur wenige bis gar keine intuitive Vorstellung davon hat, wie ein Modul aussehen sollte, wird ein gut getestetes, beschissenes Modul erstellen.
Svidgen
86

Software ist kein Haus. Die Intuition ist gut, aber verstehen Sie, dass es nicht immer richtig ist.

Teilen Sie alle Spezifikationen in Inspektionen auf, von denen ich glaube, dass sie erforderlich sind (siehe in die Zukunft).

Das ist nicht richtig. In TDD beschreiben Sie, wie Sie den Code verwenden möchten. In den technischen Daten heißt es: "Es muss ein Haus geben, das man betreten kann." Der Test sagt dann: "Hey, ich möchte eine Vordertür mit einem Knauf haben." Dies ist weitaus weniger ein Blick in die Zukunft als der Einstieg in den Bau eines Türrahmens, eines Knopfs, eines Schlosses usw. (so lautet das Argument).

Rufen Sie den Inspektor täglich zurück (vorbei an 2/100).

Das stimmt nicht. Sie schreiben keine Tests für das Haus. Sie schreiben Tests für den Vordertürrahmen und machen sie dann grün. Dann wird geprüft, ob die Tür fest und grün ist. Sie sollten vielleicht ein Dutzend oder so Tests zu einem bestimmten Zeitpunkt höchstens gebrochen haben. Normalerweise ist es eher zwei vor vier.

Außerdem impliziert die Analogie "Rufe den Inspektor aus", dass die Person einige Zeit braucht, um herauszukommen und ihre Arbeit zu erledigen. Das Ausführen von Unit-Tests für eine TDD-Iteration sollte buchstäblich einige Sekunden dauern.

Es scheint, dass Änderungen schneller vorgenommen werden können und ohne den Overhead TDD zu erstellen scheinen.

Der Aufwand ist geringer als Sie vermuten. Ein paar Sekunden, um die Tests vielleicht ein halbes Dutzend Mal auszuführen, sind für die gesamte Entwicklungszeit unerheblich.

Das Problem von dev besteht manchmal darin, dass Sie beim Testen feststellen, dass es ein großes Problem gibt. Als würde man das Bett neben die Toilette stellen und niemand möchte dort ein Problem haben. Dinge, deren Behebung länger dauert als jeglicher TDD-Aufwand. Dinge, die TDD abgefangen hätte, da TDD Sie von Anfang an dazu zwingt, Ihren Code zu verwenden und darüber nachzudenken, wie Sie mit ihm interagieren können.

Bei meinen Professoren am College drehte sich alles um die Idee von Tests, dann Code, dann Test.

Alles in allem ist TDD nicht allgegenwärtig. Viele Orte entwickeln noch immer zuerst und viele der angeblichen Vorteile von TDD sind übertrieben. Wichtig ist, dass Sie die Tests machen und sie gut machen. Die Reihenfolge, in der Sie die Arbeit erledigen, ist weniger wichtig.

Telastyn
quelle
18
+1 nur für den letzten Absatz. Ihre Hausbeispiele unterstreichen wirklich, wie dumm "religiousTDD" sein kann.
Robert Harvey
23
"Was wichtig ist, ist, dass Sie die Tests machen und sie gut machen. Die Reihenfolge, in der Sie die Arbeit machen, ist weniger wichtig. " Ich bin ein großer Fan von Test-Driven-Development (TDD) und setze mich oft dafür ein. Das Schreiben von Code ist jedoch unübersichtlich. Bei schwierigeren, weniger genau definierten Problemen muss ich in der Regel zuerst Code schreiben, bevor ich die Anforderungen verstehen kann. Dann kann ich die Anforderungen und dann die Tests schreiben.
Trevor Boyd Smith
1
@ TrevorBoydSmith würden Sie nicht die Dokumentation zu diesem Zeitpunkt schreiben, nicht die Anforderungen.
Nerdlyist
8
Da TDD die Perspektive des Anwenders des Codes einbezieht, fördert es im besten Fall bessere Schnittstellen. Wenn ich zum Beispiel anrufe, open_doorsollte ich keine Flagge für übergeben müssen toilet_flushed. Deshalb schreibe ich meinen Test nicht so und deshalb hat mein Code diese "Ecken und Kanten" nicht. Code, der völlig ohne ausreichende Berücksichtigung der Art und Weise geschrieben wurde, in der er aufgerufen wird, weist häufig seltsame Schnittstellen oder Annahmen / Voraussetzungen auf.
brian_o
3
@ TrevorBoydSmith Um es zu benennen, ich habe gehört, dass es "Spike & Stabilize" heißt, und ja, es ist eine praktische Technik, um herauszufinden, wie man etwas macht, von dem man noch nicht weiß, wie man es macht.
RubberDuck
13

Die Ähnlichkeiten zwischen dem Erstellen einer physischen Sache und dem Schreiben von Software sind ziemlich gering.

Trotzdem gibt es einen großen Unterschied, auf den wir hinweisen sollten:

Es gibt einen Unterschied zwischen "Verfassen eines Tests" und "Ausführen eines Tests".

Im Beispiel ein Haus zu bauen, die Anforderungen und Prüfungen haben Sie vor dem physischen buildout. Und Teile der Testsuite werden ununterbrochen ausgeführt - sogar von mehreren Agenten! Wenn der Erbauer einen 2x4 aufnimmt, "testet" er die Einheit sofort und automatisch anhand seiner Vorstellung, "wie ein 2x4-Sound aussieht". Er verfasst keine Anforderungen, nachdem er sie aufgegriffen hat. Er führt bereits bestehende Überprüfungen durch.

Ebenso für eine montierte Wand, einen Elektrokasten, die Rohrleitungen usw. - die Prüfungen / Anforderungen sind bereits vorhanden; Sie werden implizit und automatisch von den geschulten Augen aller am Arbeitsplatz tätigen Personen ausgeführt . Eine weitere Reihe bereits vorhandener Tests wird ausgeführt, wenn der Inspektor sie besucht. Wenn die Einheiten nicht so gebaut wurden, dass sie diesen bereits vorhandenen Test bestehen, schlagen sie fehl.

Und ebenso für die Struktur als Ganzes. Die Pläne bestehen bereits vor dem Buildout. Bei jedem Schritt auf dem Weg arbeiten die Ingenieure an einer Reihe von Bedingungen, unter denen die Struktur nach Abschluss des Ausbaus letztendlich getestet wird.

Allerdings muss nicht jedem physischen Projekt eine riesige Reihe von Tests vorausgehen. Wenn Sie in Ihre Werkstatt gehen und anfangen, Holz für eine Spielzeugkiste oder etwas anderes zusammenzustellen, und sich von Ihrer Intuition und Kreativität leiten lassen, ist das keine rigorose TDD-Holzbearbeitung. In diesem Fall verlassen Sie sich grundsätzlich auf die physikalischen Gesetze des Mediums und Ihre groben Erwartungen, um die Arbeit zu validieren (dh "Wenn es kompiliert und funktioniert, ist es gut!").

Und das ist in Ordnung. Nicht allen muss ein strenger Test vorausgehen.

tl; dr

Auch wenn Bauen! = Software schreiben: Bauen funktioniert testgetrieben. Die „passing“ Bedingungen für jede Einheit tun ihre buildout vorangestellt werden .

Kombinieren Sie "Tests ausführen" nicht mit "Tests schreiben".

Nicht alles muss TDD sein.

Svidgen
quelle
Ich bekomme Code! = Physikalisch ist eine Analogie. Aber das klärt tatsächlich ein bisschen mehr für mich auf. Wie mein anderer Kommentar zeigt, frage ich mich, ob dies den Test zuerst erschwert, den Wunsch zurückzugehen und jetzt größere Änderungen vorzunehmen.
Nerdlyist
@nerdlyist In gewisser Weise ja. Aber wenn Ihre Tests die "richtigen" Dinge überprüfen, ist es eine "Behinderung", die Sie wollen .
Svidgen
4
Zurück zur Hausanalogie: Wenn Ihr Kunde plötzlich einen anderen Türstil austauschen möchte und er nicht die gleichen Abmessungen hat, ändern sich die Anforderungen an die Tür- und Öffnungsabmessungen, und die Arbeit erfordert Änderungen an diesen "Tests" "sollte die Arbeit widerspiegeln, die erforderlich ist, um die Implementierung zu ändern. Aber es gibt viele Tests, die sich nicht ändern: Die Tür muss sich öffnen und schließen, verriegeln und im geschlossenen Zustand in der Öffnung P% luftdicht sein, usw. Viele Tests, die das "Hindernis" nicht ändern körperliche Veränderungen angemessen .
Svidgen
1
Wenn ich noch einmal +1 geben könnte, wäre es hilfreich, das letzte Bit in Betracht zu ziehen. Nicht alles braucht einen Test. Auch das erneute Lesen ließ mich denken, dass ich TDD-Komponententests mit Integrations- und Regressionstests verschmelze. Die Mitarbeiter testen automatisch die Einheiten, die der Inspektor integriert, und die Regressionstests werden durchgeführt, wenn größere Änderungen vorgenommen werden.
Nerdlyist
1
@nerdlyist Integrations- und Regressionstests können auch zuerst durchgeführt werden. Dies passt nicht ganz zum Entwicklungszyklus der "TDD-Dogmatiker", aber das Ergebnis ist im Großen und Ganzen dasselbe: Sie erhalten testbaren Code mit minimalem Fremdcode und Tests, die tatsächlich bestätigen, was sie behaupten. Das Testen, nachdem Sie den Code geschrieben haben, kann die Ausführung einiger oder aller dieser Aufgaben etwas erschweren. Gar nicht unmöglich, aber möglicherweise schwieriger.
Svidgen
11

Sie sind in die Falle gegangen, wenn Sie glauben, dass das Schreiben von Software dem Bauen eines Hauses entspricht. Ist es nicht. Es ist analog zur Erstellung der Architektenzeichnungen und der Berechnungen der Tragwerksplaner.

Jetzt mit echten Häusern erstellt der Architekt diese Pläne im Voraus. Dann rufen Sie die Bauherren an, die mit dem Bauen beginnen, auf Probleme stoßen, Dinge ändern, die Gebäudesteuerung übernehmen, Änderungen wünschen usw. Am Ende kommt der Architekt zurück und fordert Sie auf, seine Zeichnungen entsprechend zu aktualisieren Was ist passiert. Dies ist eine beschissene Vorgehensweise, aber der Bau von Häusern dauert lange und ist teuer. Es ist daher die einzig praktikable Vorgehensweise.

Für das Software-Engineering sieht es besser aus. Das Äquivalent zu dem Gebäude, in dem sich das Haus befindet, besteht darin, dass der Compiler Ihren Code in eine kompilierte Einheit (Bibliothek, App, Web-App usw.) umwandelt. Es ist sehr schnell und billig, dies hunderte Male am Tag zu tun. Daher ist es nicht sinnvoll, das Haus beim Hinzufügen von Funktionen wiederholt neu zu erstellen und den Inspektor (QS) erst am Ende zum Testen aufzurufen. Wenn Sie diese Überprüfungen automatisieren, kann der Inspektor stattdessen bei jeder Neuerstellung alles erneut überprüfen.

Es spielt keine Rolle, ob Sie eine strenge TDD oder einen eher testorientierten Ansatz für das Schreiben von Code als für einige Tests verfolgen . Ich bevorzuge den ersten Ansatz, andere den letzteren. Wählen Sie diejenige, die zu Ihnen passt. Wichtig ist, dass Sie diese Schecks im Laufe der Zeit erstellen. Sie helfen später, wenn Sie den Code ändern möchten, indem sie Sie vor Funktionsunterbrechungen an anderer Stelle warnen, wenn Sie etwas ändern.

David Arno
quelle
1
Ich sehe, Sie haben sich dann mit Gebäudesteuerung befasst ... :)
Jules
5
"Dies ist eine beschissene Art, Dinge zu tun, aber Häuser brauchen viel Zeit zum Bauen und sind teuer, daher ist dies die einzig praktikable Art.": Es ist wahr, dass Sie Software sehr schnell neu erstellen können, aber wenn Sie einen Fehler machen Entscheidung am Anfang müssen Sie möglicherweise später eine große Umschreibung. Inkrementelles Design löst solche Probleme nicht immer: Man bewegt sich in kleinen Schritten, bis man sich in einer Sackgasse befindet und zurück muss. Es gibt keine Silberkugel.
Giorgio
2
@ Giorgio - große Umschreibungen passieren, weil einzelne Entscheidungen an vielen Stellen im Code wiedergegeben werden. Wenn sich die Entscheidung ändert, ändert sich der Code an vielen Stellen. Durch kontinuierliches Refactoring wird dieses Problem gemindert, indem Duplikate unterdrückt und die Codemenge begrenzt werden, die eine einzelne Entscheidung widerspiegelt. Eine gute Testabdeckung unterstützt kontinuierliches Refactoring.
Kevin Cline
7

In erster Linie sind die Vorlaufkosten nicht so hoch, wie Sie denken . Ja, Sie verbringen mehr Zeit mit dem Testen, als wenn Sie keine Tests durchführen. Aber wenn Sie eine "Test nach" -Methode durchführen, was verschwenden Sie dann wirklich? Nehmen wir an, TDD dauert 10 Stunden und DDT dauert 6 Stunden. Ihre "zusätzlichen" Vorabkosten betragen nur 4 Stunden. Wenn Sie jetzt eine Codemetrik oder eine Anforderung wie 90% Deckung anwenden, werden Ihre TDD- und DDT-Kosten noch enger.

Mit TDD schreiben Sie weniger fehlerhaften Code. Auch wenn dies nur daran liegt, dass Sie die Anforderungen als Test formuliert haben, können Sie am Ende des Tages nachweisen, dass Ihr Code genau das tut, was Sie von ihm wollten. Vielleicht wollten Sie, dass es das Falsche tut, aber das ist kein Fehler, der eine Änderungsanforderung ist. Das ist wichtig. Es ist einfacher, ein funktionierendes Produkt zu "verkaufen", könnte aber anders / besser funktionieren, als ein Produkt zu verkaufen, das als nicht funktionierend wahrgenommen wird. Mit TDD ist es buchstäblich unmöglich, den Test zu bestehen und nicht funktionierenden Code zu schreiben. Möglicherweise haben Sie die Anforderungen nicht verstanden und den falschen, aber funktionierenden Code geschrieben.

TDD ist besser, je älter die Codebasis wird. Versuchen Sie, das Refactoring ohne oder mit einer schlecht implementierten Testsuite durchzuführen. Schon eine einfache Änderung kann zu Fehlern führen. Mit einer Test-Suite mit guter Abdeckung wird sichergestellt, dass das Produkt bei seiner Weiterentwicklung weiterhin wie gewünscht funktioniert. Es hilft auch, widersprüchliche Geschäftsregeln hervorzuheben (die über längere Zeiträume hinweg auftreten).

Sie wissen nicht, dass es nicht funktioniert. Ohne eine Testsuite wissen Sie nicht, ob Ihr Code so funktioniert, wie Sie es glauben, oder ob er nur zu funktionieren scheint.

var foo = function(in) {
    if(in == 0) {
      return true
    }
}

Jetzt rufen Sie in Ihrer gesamten Anwendung an. if(foo()){ doStuff() }Was passiert, wenn ich foo behebe?

var foo = function(in) {
    if(in === 0) {
      return true
    }
}

Sie sollten auch Ihre Tests überarbeiten und trocknen . Eine gute Testsuite ist nicht schwer zu warten. Mit gut geschriebenen Atomtests musste ich selten mehr als 1-2 von ihnen gleichzeitig ändern. Bei größeren Änderungen an der Testsuite ist es eine riesige rote Fahne, dass etwas nicht stimmt.

Ich sehe nur nicht, wie ich alle meine Methoden kennen sollte und wie die Dinge funktionieren, bis mein Code da ist.

Das solltest du nicht. Sie sollten einen Test schreiben, der prüft, ob eine Arbeitseinheit erledigt ist. Wenn Sie das Gefühl haben, Dinge zu testen, von denen Sie möglicherweise nichts wissen, denken Sie zu groß, ODER Tests sind zu klein.

Zum Beispiel müssen Sie wissen, dass eine Tür sich schließt und sich verriegelt. Ich würde door.close () und door.lock () testen und door.open () gibt false zurück, wenn die Tür verschlossen ist. Das ist es. Wenn Ihre Tests door.lock () sind, setzt es ein Flag in der Datenbank. Dann testen Sie zu klein. Der Test muss nicht wissen, wie door.lock () funktioniert, nur dass es funktioniert.

Wenn Sie jetzt einen Test schreiben, der besagt, dass house.isSecure () true zurückgibt, wenn alle Türen und Fenster gesperrt sind. Ohne zuerst auf Türen oder Fenster zu schauen, denkt man zu groß.

Schließlich sehen Sie möglicherweise eine zu große Arbeitseinheit . Wenn Sie Ihre Anforderungsliste erhalten, sollten Sie diese so organisieren, dass Sie an der kleinsten Einheit arbeiten. Schreiben Sie den Test nur für diese Einheit, dann den Code, dann spülen und wiederholen.

Im Wesentlichen ist Ihr Verständnis (die Liste), wie TDD funktionieren sollte, ausgeschaltet. Sie sollten niemals 2/100 verpassen. Sie sollten 1/1 Passing, dann 2/2 Passing, dann 3/3 Passing, dann 4/4 Passing und so weiter haben.

Eine überarbeitete Liste für Sie

  1. Holen Sie sich alle Spezifikationen
  2. Wählen Sie eine Spezifikation aus
  3. Probier es aus
  4. Code es
  5. Probier es aus
  6. Wenn die Tests erfolgreich sind, gehe zu 7, sonst gehe zu 4
  7. Wenn Sie alle Spezifikationen erfüllt haben, fahren Sie mit 8 fort, ansonsten fahren Sie mit 2 fort
  8. Überprüfen Sie die Spezifikationen mit dem Verbraucher und fügen Sie bei Bedarf neue Spezifikationen hinzu. Bei korrekter Ausführung sollten Sie keine Tests ändern müssen. Fügen Sie einfach neue hinzu. Manchmal kann das Sammeln von Anforderungen auseinanderbrechen und Sie müssen Tests hinzufügen, die mit früheren Tests in Konflikt stehen, aber Sie sollten selten Tests ändern müssen.
coteyr
quelle
2
Diese Antwort gefällt mir, weil sie die wirklichen Vorteile von TDD hervorhebt - die Verwaltbarkeit älterer Codebasen. Viele Leute, die nur auf der grünen Wiese eines Projekts gearbeitet haben, sehen den Vorteil von TDD nicht, weil es so aussieht, als wäre es nur zusätzliche Arbeit. Es zahlt sich wirklich aus, wenn Sie eine vorhandene Codebasis aktualisieren und warten müssen. Ich wünschte, in der Schule würden sie Ihnen ein Projekt geben, und sobald Sie es zum Laufen bringen, fordern Sie eine Reihe von Funktionsänderungen an. Dies würde die Realität besser widerspiegeln und den Wert von TDD demonstrieren.
thomij
1
Diese Antwort gefällt mir auch. Beachten Sie, dass wir in der Regel vergessen, wie viel Zeit wir tatsächlich mit der manuellen Ausführung von Tests verbringen: Bearbeiten, Kompilieren, Durchgehen, manuelles Debuggen, Wiederholen. TDD automatisiert einen Großteil davon.
Technophile
Das, was mir hier auffällt, ist, dass es wichtig ist, zu beachten, dass Sie beim Schreiben eines Komponententests in TDD keinen Test für ein Teil der Clientfunktionsspezifikation schreiben, sondern einen Test für das Verhalten des unit, wie Sie es als Programmierer in Ihrem Gehirn definiert haben: "Diese Klasse sollte ein Ereignis auslösen, wenn X eintritt, schreiben wir einen Test dafür." Diese vage "Ihre Tests sind Ihre Spezifikation!" Rhetorik ist großartig, wenn Sie bereits TDD erhalten, aber für jemanden, der aus der Schleife geraten ist, wirft sie mehr Fragen auf als sie beantwortet.
Ant P
4

Es gibt einige Schlüssel, von denen ich denke, dass die anderen Antworten fehlen.

Drei Vorteile

Erstens sind die Fehler- und Änderungskosten zwischen Software und einem Haus so unterschiedlich, dass einige Regeln möglicherweise nicht zutreffen. Zum Beispiel sind die Kosten für das Testen einer physischen Struktur so hoch, dass Sie ein hohes Maß an Vertrauen in deren Funktion benötigen, um das Testen nicht zu verschwenden. Wenn Sie mit Software eine Reihe von Komponententests in 1 bis 5 Sekunden ausführen können, stehen Ihnen verschiedene Optionen zur Verfügung.

Zweitens besteht der Zweck der Ausführung eines Tests, von dem Sie erwarten, dass er fehlschlägt, bevor Sie den zu testenden Code schreiben, darin, den Test selbst zu überprüfen. Sicher, es kann albern oder verschwenderisch wirken. Aber ich habe genug Unit-Tests gesehen, die so geschrieben wurden, dass sie immer Bestand haben, auch wenn der zu testende Code kaputt ist. Dies kann leicht passieren, wenn Sie den zu testenden Code schreiben, manuell testen und dann den Komponententest schreiben. Wenn Sie einen Komponententest schreiben, sehen Sie, dass dieser fehlschlägt. Wenn Sie dann den Code schreiben, der zum Bestehen des Tests erforderlich ist, und der Test besteht, wissen Sie, dass der Test einwandfrei ist. Wenn der zu testende Code zurückgeht, besteht eine vernünftige Chance, dass Ihr Komponententest ihn abfängt.

Ein dritter Vorteil von TDD, der nicht oft erwähnt wird, ist, dass die resultierende Codegröße und -komplexität oft eine Größenordnung kleiner ist. Ich war immer stolz darauf, einfachen und präzisen Code zu bevorzugen. Bis ich anfing TDD zu üben. TDD hat mir gezeigt, dass das, was ich vorher getan hätte, übermäßiger Code wäre. Warum passiert das? Weil Sie einen Test schreiben, schreiben Sie dann Code, um den Test zu bestehen. Wenn der Test bestanden ist, sind Sie damit fertig. Wenn Sie in dieser Denkweise sind, ist es schwierig, versehentlich "zusätzlichen" Code zu schreiben.

(Zusätzlicher Code war ein Problem, das ich bei einem Produkt beobachtet habe, an dem ich gearbeitet habe. Schwerwiegende Probleme aufgrund von Code, nach dem niemand gefragt hat, aber einige Entwickler dachten, er wäre cool.)

Kostenanalyse

In gewisser Hinsicht haben Sie also Recht. Wir konnten mit dieser Strategie beim Hausbau nicht durchkommen. Es wäre zu teuer. Aber Software ist kein Haus. Software ist billig.

Eine Analogie mit einem Haus ist die Arbeit des Zusammenbaus des Hauses gegenüber einem Software-Compiler.

In einer Welt ohne TDD iterieren Entwickler immer noch. Wir folgen einem Code -> Kompilieren -> Ausführen -> Testzyklus. Wir befinden uns bereits in einem Modell, das wesentlich vom Hausbau abweicht. Wenn Ihre Bauarbeiter einen Türrahmen bauen, dann eine Tür bauen und dann den Rahmen neu bauen müssen, weil die Tür zu groß dafür ist, haben Sie ein Kostenproblem. So verbringen Sie mehr Zeit im Voraus, um sicherzustellen, dass Sie alles perfekt erhalten. Bei der Programmierung können die meisten Projekte in Sekunden oder Minuten kompiliert werden, sodass es keine Rolle spielt, ob etwas von Anfang an fehlerhaft ist. Die Kosten für das Vorausdenken über Kleinigkeiten überwiegen normalerweise die Kosten für das Neukompilieren. So kompilieren wir die ganze Zeit neu.

TDD ist das gleiche Prinzip, nur gedreht, damit der Test im Vordergrund steht. Wenn das Testen supergünstig ist (alles läuft in Sekunden), überwiegen die Kosten für das Durchdenken des Gesamtbilds, der perfekten Gesamtlösung in einer einzigen Big-Bang-Codierungsiteration, die Kosten für das Refactoring.

Außer...

Es gibt einige Dinge in der Programmierung, bei denen diese Argumente nicht zutreffen. Das ist der Zweck der Architektur. Identifizieren und planen Sie im Voraus Bedenken, deren spätere Änderung teurer sein wird. Sie würden zum Beispiel keine Datenbank im Handumdrehen auswählen, ohne über Ihre Bedürfnisse nachzudenken, mit dem Aufbau zu beginnen und einfach zu argumentieren, dass Sie sie später ändern können. Sie müssen es durchdenken.

Brandon
quelle
1
Toller Punkt, um den Test zu verifizieren! Außerdem: Wenn Sie ein Haus bauen, ist es SCHWER, eine Wand zu bewegen (und dies hinterlässt Narben). Mit Software ist das Verschieben von Code relativ einfach - vorausgesetzt, Sie haben einen automatisierten Test, um unbeabsichtigte Änderungen zu erfassen.
Technophile
4

Ich habe mich oft darüber gewundert, bis ich ein paar Projekte von TDD gemacht habe. Es gibt eine sehr prägnante und umfassende Erklärung, die mir dabei aufgefallen ist:

Wenn Sie Code schreiben, müssen Sie sicherstellen, dass der Code etwas Bedeutendes bewirkt. So testen Sie Ihren Code. Sie können Ad-hoc-Tests durchführen. Testen funktioniert jedoch besser, wenn Sie überlegen, wie Sie testen sollen, bevor Sie anfangen, Dinge zu tun. Sie entwerfen also die Teststrategie, bevor Sie mit dem Testen beginnen.

Nun, da Sie über Ihre Teststrategie nachdenken, können Sie zumindest einen Teil davon auch automatisieren ... Und siehe, Sie haben eine gewisse TDD-Ebene. Die Tatsache, dass Sie Code schreiben, bis Sie den Test bestehen, ist normal. Das ist, was Sie sowieso tun, schreiben Sie Code, bis es funktioniert. Es ist jetzt einfach, die Tests zu sprengen.

Aus Gründen, die den Rahmen sprengen, schreiben Sie nicht alles auf einmal. Sie entwerfen die Tests also auch nicht auf einmal. Aber im Grunde ist es das, was es ist. Nur eine bessere Planung der Tests, Sie schreiben Test nicht immer im Voraus. Manchmal fügt man im Laufe der Zeit mehr hinzu und findet Fehler, die man nicht erwartet hat, oder macht den Test später robuster. Und manchmal müssen Sie möglicherweise keine Tests entwerfen, sondern es ist mühsam, manuell zu testen, damit Sie die Tests später durchführen können.

TDD ist also nur eine extreme Methode, um zu sehen, wie Sie Ihre Arbeit validieren.

joojaa
quelle
4

Obwohl diese Frage meiner Meinung nach bereits eine akzeptierte Antwort hat, muss ich etwas hinzufügen, das von einem Designstil ohne schriftliche Prüfung (alle von "Testern" nach einem Testverfahren manuell durchgeführten Tests) an TDD stammt. Dies sind nur meine persönlichen Beobachtungen, obwohl ich glaube, dass sie ziemlich universell sind.

Wenn Sie etwas Neues schreiben, etwas, das Sie noch nie zuvor getan haben, gibt es keinen signifikanten Unterschied zwischen TDD und TDD.

Im Allgemeinen schreiben Sie ein kleines Stück Code, um eine Idee zu untersuchen, fügen dann einige fest codierte Bits zum "Testen" hinzu und kompilieren und / oder führen sie dann aus. Wenn es funktioniert, löschen Sie das fest codierte Material und verallgemeinern den Code, indem Sie Parameter, Instanzvariablen usw. hinzufügen.

Denk darüber nach. Das ist genau so viel Arbeit wie bei TDD. Der einzige Unterschied besteht darin, dass Sie in TDD die "Test" -Bits separat in eine andere Datei schreiben und sie am Ende nicht löschen. In TDD behalten Sie Ihren Testcode .

Wenn TDD etwas besser organisiert ist, bedeutet dies natürlich, dass ein wenig mehr Arbeit erforderlich ist, um herauszufinden, wie Sie die Test-Codebits von Ihrem tatsächlichen Code trennen können. Wenn Sie jedoch Unit-Tests geschrieben haben, lernen Sie, wie Sie Ihren Code zum Testen modularisieren.

Slebetman
quelle
2

Warum dreht sich bei Agile alles um die testgetriebene Entwicklung (TDD) und nicht um den entwicklungsgetriebenen Test (DDT)?

Ich zwitschere nur hier rein, weil ich finde, dass die Frage eine Tatsache nahelegt ("agil dreht sich alles um TDD"), die ich eher ablehnend finde. Alle Antworten scheinen diese Tatsache als selbstverständlich anzusehen. Sie sind gute Antworten, wenn Sie davon ausgehen, dass es bei Agile in erster Linie um TDD geht (auch bekannt als Testen auf Geräteebene).

https://en.wikipedia.org/wiki/Agile_software_development#Agile_methods listet ein gutes Dutzend oder mehr verschiedene Entwicklungsmodelle auf.

Als Denkanstoß biete ich besonders Verhaltensorientierte Entwicklung und Funktionsorientierte Entwicklung an. Völlig andere Bestien, die auch zu allen Vorteilen der grundlegenden TDD führen können, aber weit von einem einfachen Rot-Grün-Refaktor-Zyklus entfernt sind.

Meine Antwort lautet also:

  • "DDT" (auch bekannt als das Schreiben von Tests nach oder über der Implementierung) funktioniert aus realen Gründen nicht. Sobald Sie Zeit oder Gelddruck bekommen, gehen die Tests aus dem Fenster; und nur Tests zum Nutzen von Tests zu haben, ist mir sowieso lieber, IMO.
  • Bei Agile geht es nicht nur um testgetriebene Entwicklung (TDD), wenn Sie diesen Begriff als "Komponententests für alle Bausteine ​​/ Klassen" interpretieren (was zumindest laut Wikipedia der Fall ist). TDD ist nur eine Möglichkeit zur agilen Entwicklung.
  • Es gibt andere Methoden wie BDD oder FDD, die einen Full-Stack-Ansatz verwenden. Sie schreiben immer noch Ihre Szenarien im Voraus, Sie haben immer noch einen Rot-Grün-Refaktor-Zyklus und Sie implementieren immer noch nur, bis Ihre Szenarien grün sind, aber Ihre "Tests" üben per Definition die gesamte Software aus (indem Sie sich wie eine Benutzerinteraktion verhalten) und niemals nur eine einzige Einheit.

Ich hätte lieber eine Anwendung mit vollständiger BDD / FDD-Abdeckung und keinen Unit-Tests als eine mit vollständiger Unit-Test-Abdeckung und keinen Full-Stack-Tests.

(TDD hat natürlich seinen Platz, zum Beispiel in APIs, aber darüber reden wir hier nicht.)

Auch hier versuche ich nicht, alle anderen Antworten herabzusprechen. Ich möchte nur darauf hinweisen, dass die Frage ziemlich eng formuliert ist und das Feld viel mehr zu bieten hat.

AnoE
quelle
Ich wusste von dem anderen, aber zu der Zeit schien es nur sinnvoller zu sein, dies zu schreiben. Möchten Sie näher erläutern, warum TDD für API besser ist? Wie würde sich die Verwendung auf einem Webclient mit MVC unterscheiden?
Nerdlyist
1
Bei APIs ist es äußerst wichtig, dass sie einen sehr detaillierten Vertrag einhalten. Jeder Methodenaufruf muss sich für die Benutzer (bei denen es sich um andere Programme handelt) sehr vorhersehbar verhalten, damit er ordnungsgemäß verwendet werden kann. Dies ist, wo Unit-Tests wirklich glänzen. OTOH, in einer Anwendung ist es am wichtigsten, dass die Funktionen, die Benutzer Ihres Menschen benötigen, wie beabsichtigt funktionieren. Sicher, Ihre "Interna" sind auch besser korrekt, aber es ist wichtiger, eine gute Abdeckung der "End-to-End" -Funktionalität (dh von der Benutzeroberfläche bis in die Datenbank und zurück) zu haben, als jede einzelne Methode zu testen (welche) die menschlichen Endbenutzer sehen sowieso nicht).
AnoE
Natürlich ist hier alles in verschiedenen Graden - es kann sinnvoll sein, auch hier ein paar Unit-Tests zu haben, wenn Sie irgendwo sehr komplizierte Methoden / Klassen haben sollten (zum Beispiel: Entfernungen zwischen Geokoordinaten berechnen); Der Hauptteil (z. B. in Geschäftsanwendungen) ist jedoch der gesamte Workflow.
AnoE
0

Obwohl Sie es nicht oft so geschrieben sehen, ist der Grund für Agile, dass das Neuschreiben von Code besser ist als das Schreiben beim ersten Mal. Jedes Mal, wenn Sie Code neu schreiben, verbessern Sie den Code und verbessern sich. Das erste Mal "richtig" zu machen, ist in der Regel langsamer und spröder.

Die Haus-Analogie ist gar nicht so schlecht, aber man muss sich überlegen, wie lange wir über Hausbau Bescheid wissen und wie lange wir über Software-Engineering Bescheid wissen - auch die Komplexität des Software-Engineerings kommt dem Aufbau einer langen Brücke näher oder 20-stöckiger Turm als ein Haus. Wir sollten auch bedenken, dass mit dem Bau neuer Sprachen und Werkzeuge jeder Bauherr das Gebäude mit völlig anderen Formen, Größen und Materialien bauen wollte. Komplettes Chaos.

Das Prüfen ist jedoch keine gute Analogie zum Testen von Code. In der Software sind wir noch nicht einmal so weit, dass wir anständige Inspektoren haben (ausgenommen Ihre Kollegen mit unterschiedlichen Qualifikationen). Wir haben auch keine Vorschriften, an denen wir uns orientieren müssen, außer vielleicht einigen meist willkürlichen "Kodierungsstandards" (die eher dem Testen der Farbe Ihres Lacks und Ihres Rasenlayouts als der Struktur gleichen).

Test-first ist eher so, als würden Sie eine Mauer bauen, als wenn Sie etwas Druck darauf ausüben, um die Stabilität zu gewährleisten, bevor Sie sie anheben und auf Ihr Haus stellen. Es ist so, als würde man das Fenster vermessen, um sicherzustellen, dass es in das Loch passt, das Sie verlassen haben, bevor Sie versuchen, es zu platzieren.

Wenn Sie eine Reihe von Brücken ohne unsere jahrhundertelangen Architekturkenntnisse, Muster, Vorschriften und Berechnungen bauen müssten, die wir derzeit nachweisen müssen, dass unsere Brücken funktionieren, bevor wir sie bauen, würden Sie Ihre Brücken wahrscheinlich viel testen und neu bauen.

Endlich ein Punkt, bei dem es sich nicht um eine Analogie handelt: Mit Software können Sie jedes Mal, wenn Sie einen Teil Ihres Codes neu schreiben, sowohl Ihren Code als auch Ihre Fähigkeiten erheblich verbessern. Nutzen Sie jede Chance, um Code neu zu schreiben. TDD kann eine gute Entschuldigung sein.

Bill K
quelle