2010-08-20 4 views
14

Betrachten Beiträge wie this und andere, scheint es, dass die richtige Art TDD zu tun ist, einen Test für ein Feature zu schreiben, nur diese Funktion zu übergeben, und fügen Sie einen weiteren Test und Refactor nach Bedarf, bis es passiert, dann wiederholen .Warum sollte ich bei TDD "gerade genug" tun, um einen Test bestanden zu bekommen?

Meine Frage ist: Warum wird dieser Ansatz verwendet? Ich verstehe die erste Idee der Schreibtests vollständig, weil sie Ihrem Design hilft. Aber warum sollte ich nicht alle Tests für eine bestimmte Funktion erstellen und diese Funktion dann auf einmal implementieren, bis alle Tests bestanden sind?

Antwort

11

Der Ansatz stammt aus dem Prinzip der extremen Programmierung von Sie werden es nicht brauchen. Wenn Sie tatsächlich einen einzelnen Test schreiben und dann den Code, der es durchläuft, dann wiederholen Sie diesen Prozess normalerweise, dass Sie gerade genug schreiben, um Dinge zum Laufen zu bringen. Sie erfinden keine neuen Funktionen, die nicht benötigt werden. Sie behandeln keine Eckfälle, die nicht existieren.

Versuchen Sie ein Experiment. Schreiben Sie die Liste der Tests aus, die Sie für notwendig halten. Leg es zur Seite. Dann gehen Sie mit dem einen Test auf einmal. Sehen Sie, ob die Listen unterschiedlich sind und warum. Wenn ich das mache, habe ich fast immer weniger Tests. Ich finde fast immer, dass ich einen Fall erfunden habe, den ich nicht brauchte, wenn ich es alle zuerst teste.

+0

+1 für das "Experiment" – k3b

1

Das ist eine gute Frage. Sie müssen ein Gleichgewicht zwischen dem Schreiben aller Tests im Universum der möglichen Tests und den wahrscheinlichsten Benutzerszenarien finden. Ein Test ist, meiner Meinung nach, nicht genug, und ich schreibe typischerweise 3 oder 4 Tests, die die gebräuchlichsten Verwendungen des Features darstellen. Ich schreibe auch gerne einen Best-Case-Test und einen Worst-Case-Test.

Durch das Schreiben vieler Tests können Sie die potenzielle Verwendung Ihrer Funktion vorhersehen und verstehen.

+0

Können Sie näher erläutern, was Sie unter einem Best/Worst-Case-Test verstehen? Ich sehe die Bedeutung in der realen Welt, aber ich kann mir nicht vorstellen, wie es sich auf TDD und Unit Testing bezieht. – Mathias

+0

Sie haben Recht, der "Best/Worst Case" -Test bezieht sich nicht wirklich auf TDD, sondern nur auf etwas, das ich beim Testen als sehr nützlich empfunden habe. Der beste Fall besteht darin, sicherzustellen, dass nach einer Änderung zur Behebung eines fehlgeschlagenen Tests keine Regression stattfindet. – funkymushroom

3

Ich glaube, das kommt vom Prinzip von "YAGNI" ("Du wirst es nicht brauchen") (*), das besagt, dass Klassen so einfach wie nötig sein sollten, ohne zusätzliche Features. Wenn Sie also ein Feature benötigen, schreiben Sie einen Test dafür, dann schreiben Sie das Feature und Sie hören auf. Wenn Sie zuerst eine Reihe von Tests geschrieben haben, würden Sie nur spekulieren, was Ihre API zu einem bestimmten Zeitpunkt in der Zukunft sein müsste.

(*) ich, dass im Allgemeinen übersetzen als „Sie zu dumm sind, zu wissen, was in der Zukunft benötigt werden“, aber das ist ein anderes Thema ......

0

ich tun würde, wie Sie vorschlagen. Schreiben Sie mehrere Tests für eine bestimmte Funktion, implementieren Sie die Funktion und stellen Sie sicher, dass alle Tests für diese Funktion bestanden werden. Dies stellt sicher, dass Sie den Zweck und die Verwendung der Funktion getrennt von Ihrer Implementierung verstehen.

0

Wenn Sie viel mehr Implementierungsweisen ausführen müssen, als das, was in Ihren Komponententests getestet wird, sind Ihre Komponententests wahrscheinlich nicht umfassend genug.

Ich denke, ein Teil dieser Idee besteht darin, Einfachheit zu bewahren, zu geplanten/geplanten Funktionen zu halten und sicherzustellen, dass Ihre Tests ausreichend sind.

1

Ich glaube, TDD befürwortet einen Test zu einem Zeitpunkt, zu schreiben, weil es Sie in Bezug auf das Prinzip zu tun die einfachste Sache zu denken zwingt, die möglicherweise bei jedem Schritt der Entwicklung arbeiten konnten.

3

imho es reduziert die Chance, das Stück Code, das Sie schreiben, über Engineering.

Es ist einfacher, unnötigen Code hinzuzufügen, wenn Sie sich verschiedene Nutzungsszenarien ansehen.

1

Ich denke, der Artikel, den Sie gesendet haben, ist genau die Antwort. Wenn Sie zuerst alle Tests und alle Szenarien zuerst schreiben, werden Sie wahrscheinlich Ihren Code schreiben, um alle diese Szenarien auf einmal zu behandeln, und meistens haben Sie wahrscheinlich einen Code, der ziemlich komplex ist, um all diese zu behandeln.

Auf der anderen Seite, wenn Sie eine nach der anderen gehen, werden Sie am Ende Refactoring Ihre vorhandenen Code jedes Mal, um am Ende mit Code wahrscheinlich so einfach wie es für alle Szenarien sein kann. Wie im Fall des Links, den Sie in Ihrer Frage angegeben haben, wenn sie zuerst alle Tests geschrieben hätten, wäre ich ziemlich sicher, dass sie nicht mit einer einfachen if/else-Anweisung enden würden, sondern wahrscheinlich mit einem ziemlich komplexen rekursiven Teil von Code.

2

Dan North hat vorgeschlagen, dass es kein testgesteuertes Design gibt, da das Design nicht wirklich durch Tests ausgetragen wird - dass diese Unit Tests erst Tests werden, wenn die Funktionalität implementiert ist, aber während der Designphase wirklich mit gutem Beispiel gestalten.

Dies ist sinnvoll - Ihre Tests richten eine Reihe von Beispieldaten und Bedingungen ein, mit denen das zu testende System arbeiten wird, und Sie fahren das Design basierend auf diesen Beispielszenarien aus.

Einige der anderen Antworten legen nahe, dass dies auf YAGNI basiert. Dies ist teilweise richtig.

Darüber hinaus gibt es das Problem der Komplexität. Wie oft gesagt wird, geht es beim Programmieren darum, Komplexität zu managen - Dinge in nachvollziehbare Einheiten zu zerlegen.

Wenn Sie 10 Tests schreiben, um Fälle zu decken, in denen param1 null ist, param2 ist null, string1 ist leer, int1 ist negativ und der aktuelle Wochentag ist ein Wochenende, und dann gehen Sie, um das zu implementieren eine Menge Komplexität auf einmal zu jonglieren. Dies eröffnet Platz für die Einführung von Fehlern, und es wird sehr schwierig herauszufinden, warum Tests fehlschlagen.

Auf der anderen Seite, wenn Sie den ersten Test schreiben, um eine leere Zeichenfolge1 abzudecken, müssen Sie kaum über die Implementierung nachdenken. Wenn der Test vorüber ist, geht es weiter zu einem Fall, in dem der aktuelle Tag ein Wochenende ist. Sie sehen sich den vorhandenen Code an und es wird offensichtlich, wohin die Logik gehen soll. Sie führen Tests aus und wenn der erste Test jetzt fehlschlägt, wissen Sie, dass Sie es bei der Implementierung des Wochentags-Dings gebrochen haben. Ich würde sogar empfehlen, dass Sie die Quelle zwischen den Tests festlegen, sodass Sie, wenn Sie etwas kaputt machen, immer wieder in den Status "Übergeben" wechseln und es erneut versuchen können.

Nur ein wenig nach dem anderen zu überprüfen und dann zu überprüfen, dass es funktioniert dramatisch reduziert den Platz für die Einführung von Fehlern, und wenn Ihre Tests nach der Implementierung fehlschlagen haben Sie so wenig Code, dass es sehr einfach ist, den Fehler zu identifizieren Korrigieren Sie es, weil Sie wissen, dass der vorhandene Code bereits ordnungsgemäß funktioniert hat.

4

Für mich geht es um "Gedankenlast". Wenn ich alle möglichen Verhaltensweisen gleichzeitig habe, ist mein Gehirn angespannt. Wenn ich mich ihnen einzeln annähere, kann ich der Lösung des unmittelbaren Problems volle Aufmerksamkeit schenken.

1

Der Grund für das Prinzip ist einfach. Wie praktisch es ist, sich daran zu halten, ist eine separate Frage.

Der Grund ist, dass wenn Sie mehr Code schreiben, was benötigt wird, um den aktuellen Test zu bestehen, Sie Code schreiben, der per Definition ungeprüft ist. (Es hat nichts mit YAGNI zu tun.)

Wenn Sie den nächsten Test schreiben, um den Produktionscode "aufzuholen", dann haben Sie gerade einen Test geschrieben, den Sie noch nicht gesehen haben.Der Test kann "TestNextFeature" genannt werden, aber es kann auch return true für alle Beweise, die Sie darauf haben.

TDD dreht sich alles darum sicherzustellen, dass alle Code - Produktion und Tests - getestet wird und dass alle diese lästigen "aber ich bin mir sicher, dass ich es richtig geschrieben habe" Bugs nicht in den Code.

0

Viele gute Antworten oben - YAGNI ist die erste Antwort, die in den Sinn kommt.

Die andere wichtige Sache, über die allerdings Leitlinie ‚nur das Bestehen der Prüfung erhalten‘, ist, dass TDD tatsächlich ein dreistufiger Prozess:

Red> Green> Umgestalten

Häufig der letzte Teil erneuten Besuch, die Refactoring ist, wo viel Wert von TDD in Bezug auf saubereren Code, besseres API-Design und mehr Vertrauen in die Software geliefert wird. Sie müssen in wirklich kleinen kurzen Blöcken umgestalten, damit die Aufgabe nicht zu groß wird.

Es ist schwer, sich an diese Angewohnheit zu gewöhnen, aber bleib dabei, denn es ist eine merkwürdig befriedigende Art zu arbeiten, sobald du in den Zyklus steigst.

Verwandte Themen