TDD: Mache ich es richtig?

14

Ich bin ein neuer Programmierer (lerne erst seit ungefähr einem Jahr) und in meinem Ziel, besser darin zu werden, habe ich erst kürzlich etwas über TDD gelernt. Ich wollte es mir zur Gewohnheit machen, weil es mir sehr hilfreich erscheint. Ich wollte überprüfen, ob ich es richtig benutze.

Was mache ich:

  1. Denken Sie an eine neue Methode, die ich brauche.
  2. Erstellen Sie einen Test für diese Methode.
  3. Test nicht bestanden.
  4. Schreibmethode.
  5. Test bestehen.
  6. Refactor-Methode.
  7. Wiederholen.

Ich mache das für JEDE Methode, die ich schreibe. Gibt es eine, mit der ich mich nicht beschäftigen sollte? Später überlege ich mir normalerweise eine Möglichkeit, meine bereits vorhandenen Methoden auf eine andere Art und Weise oder in einer anderen Situation zu testen. Sollte ich diese neuen Tests durchführen, an die ich denke, oder sollte ich mich nicht darum kümmern, da jede Methode bereits einen eigenen Test hat? Kann ich meinen Code ÜBERMÄSSIG testen? Ich denke, dies ist mein Hauptanliegen.

BEARBEITEN

Auch das war etwas, was ich mich nur gefragt habe. Wäre in dieser Situation TDD erforderlich, wenn Sie so etwas wie eine grafische Benutzeroberfläche erstellen? Persönlich kann ich mir nicht vorstellen, wie ich dafür Tests schreiben würde.

Cgasser
quelle
5
Sie machen das schon viel besser als erfahrene Profis, die sagen, sie testen alles (aber nicht).
Yannis
Was Sie beschreiben, ist nicht der Geist von TDD.
1
Möglicherweise möchten Sie sich mit ATDD oder BDD befassen.
Dietbuddha
Fangen Sie vielleicht höher an - denken Sie an ein neues Modul, das Sie brauchen.

Antworten:

16

Was Sie als Workflow bezeichnen, ist meiner Meinung nach nicht der Spirit of TDD.

Die Inhaltsangabe von Kent Becks Buch bei Amazon lautet:

Testgetriebene Entwicklung soll ganz einfach Angst in der Anwendungsentwicklung beseitigen.Während einige Ängste gesund sind (oft als ein Gewissen angesehen, das Programmierer auffordert, "vorsichtig zu sein!"), Glauben die Autoren, dass Nebenprodukte von Ängsten vorsichtige, mürrische und nicht kommunikative Programmierer sind, die konstruktive Kritik nicht aufnehmen können. Wenn sich Programmierteams für TDD entscheiden, sehen sie sofort positive Ergebnisse. Sie beseitigen die Angst, die mit ihrer Arbeit verbunden ist, und sind besser gerüstet, um die schwierigen Herausforderungen zu meistern, denen sie gegenüberstehen. TDD beseitigt vorläufige Merkmale, lehrt Programmierer zu kommunizieren und ermutigt Teammitglieder, Kritik zu suchen. Doch auch der Autor gibt zu, dass Mürrischkeit individuell erarbeitet werden muss! Kurz gesagt, die Prämisse hinter TDD ist, dass Code kontinuierlich getestet und überarbeitet werden sollte.

Praktisches TDD

Formale automatisierte Tests, insbesondere Unit-Tests. Jede Methode jeder Klasse ist genauso schlecht wie ein Anti-Pattern und es wird nichts getestet. Es ist ein Gleichgewicht zu haben. Schreiben Sie Unit-Tests für jede setXXX/getXXXMethode, sie sind auch Methoden!

Auch Tests können helfen, Zeit und Geld zu sparen. Vergessen Sie jedoch nicht, dass die Entwicklung Zeit und Geld kostet und dass sie Code sind, sodass die Wartung Zeit und Geld kostet. Wenn sie aufgrund mangelnder Wartung verkümmern, werden sie mehr zu einer Verbindlichkeit als zu einem Vorteil.

Wie alles in diesem Sinne gibt es ein Gleichgewicht, das nur von Ihnen selbst definiert werden kann. Jedes Dogma, egal wie, ist wahrscheinlich mehr falsch als richtig.

Eine gute Metrik ist Code, der für die Geschäftslogik von entscheidender Bedeutung ist und aufgrund sich ändernder Anforderungen häufig geändert wird. Diese Dinge erfordern formale Tests, die automatisiert sind, was eine große Rendite bedeutet.

Es wird Ihnen sehr schwer fallen, viele professionelle Läden zu finden, die auf diese Weise funktionieren. Aus geschäftlichen Gründen ist es einfach nicht sinnvoll, Geld auszugeben, um Dinge zu testen, die sich nach einem einfachen Rauchtest für alle praktischen Zwecke nicht ändern. Das Schreiben formaler automatisierter Komponententests für .getXXX/.setXXXMethoden ist ein hervorragendes Beispiel für diese völlige Zeitverschwendung.

Es ist nun zwei Jahrzehnte her, seit darauf hingewiesen wurde, dass Programmtests das Vorhandensein von Fehlern überzeugend nachweisen können, ihre Abwesenheit jedoch niemals nachweisen können. Nachdem der Softwareentwickler diese wohlbekannte Bemerkung ausführlich zitiert hat, kehrt er zur Tagesordnung zurück und verfeinert weiterhin seine Teststrategien, genau wie der Alchemist von einst, der seine chrysokosmischen Reinigungen weiter verfeinert hat.

- Edsger W. Djikstra . (Geschrieben 1988, also näher an 4,5 Jahrzehnten.)

Siehe auch diese Antwort .

Gemeinschaft
quelle
1
Das spricht ziemlich genau das an, worüber ich besorgt war. Ich hatte das Gefühl, dass ich nicht jede Methode wie ich testen sollte, war mir aber nicht sicher. Es sieht so aus, als müsste ich möglicherweise noch etwas mehr über TDD lesen.
cgasser
@ Kevincline Die meiste Zeit setXXX/getXXXwerden überhaupt nicht benötigt :)
Chip
1
Wenn Sie sich dieses triviale getXXX merken und es falsch machen oder faul in Ihr getXXX laden und es falsch machen, dann werden Sie wissen, dass Sie manchmal wirklich Ihre Getter testen wollen.
Frank Shearar
13

Du bist sehr nah dran. Versuchen Sie, auf diese etwas andere Weise zu denken.

  1. Denken Sie an ein neues Verhalten, das ich brauche.
  2. Erstellen Sie einen Test für dieses Verhalten.
  3. Test nicht bestanden.
  4. Neue Methode schreiben oder bestehende erweitern.
  5. Test bestehen.
  6. Refactor-Code.
  7. Wiederholen.

Erstellen Sie nicht automatisch Getter und Setter für jede Eigenschaft . Denken Sie nicht an eine ganze Methode und schreiben Sie den Test (s) alle Funktionen abzudecken . Versuchen Sie, die Eigenschaften in der Klasse zu kapseln und Methoden zu schreiben, um das gewünschte Verhalten zu erzielen. Lassen Sie Ihre Methoden zu einem guten Design werden, anstatt zu versuchen, sie im Voraus zu planen. Denken Sie daran, dass TDD ein Entwurfsprozess und kein Testprozess ist. Der Vorteil gegenüber anderen Entwurfsprozessen besteht darin, dass nicht mehr ein Stück Papier in den Papierkorb geworfen wird, sondern eine Reihe automatisierter Regressionstests.

Denken Sie auch an die drei TDD-Regeln von Onkel Bob .

  1. Sie dürfen keinen Produktionscode schreiben, es sei denn, es wird ein fehlerhafter Einheitentest bestanden.
  2. Sie dürfen nicht mehr von einem Komponententest schreiben, als zum Scheitern ausreicht. und Kompilierungsfehler sind Fehler.
  3. Sie dürfen nicht mehr Seriencode schreiben, als ausreicht, um den einen fehlgeschlagenen Komponententest zu bestehen.
pdr
quelle
1
@Zexanima: Es geht dir viel besser als den meisten von uns nach einem Jahr. Ich versuche nur, Sie auf den nächsten Schritt hinzuweisen.
pdr
2
Ich denke, diese 3 Regeln, mit denen du verbunden bist; So idyllisch sie auch klingen mögen, sie sind außergewöhnlich dogmatisch und in 99% aller Produktionsgeschäfte, denen jeder begegnen wird, höchst unrealistisch starr.
1
@FrankShearar oder es kann als das unpraktische Geschwätz eines fundamentalistischen Extremisten angesehen und pauschal missachtet werden. Ich habe in Geschäften gearbeitet, die diese dogmatische Einstellung hatten, sie nahmen das Dogma wörtlich und verfehlten den Punkt; Schreiben von Tests, bei denen keiner der tatsächlichen Codes auf praktische Weise getestet wurde, und Testen der Fähigkeit von Mocking and Dependency Injection-Frameworks, im besten Fall zu verwechseln, was wichtig war.
1
@pdr Der Geist von etwas ist der dogmatisch formalisierten Heiligsprechung dieses Dings diametral entgegengesetzt. Es ist eine Sache, eine Philosophie zu haben und eine andere, sie in eine Religion zu verwandeln . Über TDD wird mehr als oft in dogmatischen religiösen Begriffen gesprochen. Diese drei Regeln klingen dogmatisch und religiös, und was gehört wird, ist das Test, Test, Test- Mantra für jemanden wie das OP. Sie nehmen sie wörtlich und das schadet mehr als es nützt. Ich habe Frank entgegnet, dass polarisierende Aussagen der Sache mehr schaden als nützen können.
2
Mein Punkt war, dass Dogmatismus daraus resultiert , etwas blind als Evangelium zu akzeptieren . Nehmen Sie die polarisierende Aussage, probieren Sie sie aus und lassen Sie sich aus Ihrer Komfortzone zwingen. Sie können die mit TDD verbundenen Kompromisse nicht bewerten, wenn Sie den extremen 3-Punkte-Alles-oder-Nichts-Ansatz nicht ausprobieren, da Sie keine Daten haben .
Frank Shearar
5

Einige Dinge, die man zu den Antworten anderer hinzufügen kann:

  1. Es gibt so etwas wie überprüfen. Sie möchten sicherstellen, dass sich Ihre Komponententests so wenig wie möglich überlappen. Es hat keinen Sinn, dass mehrere Tests dieselben Bedingungen in demselben Code überprüfen. Wenn Sie andererseits Ihren Produktionscode überarbeiten und viele Tests haben, die sich mit diesem Abschnitt überschneiden, müssen Sie alle diese Tests korrigieren. Wenn sie sich nicht überlappen, unterbricht eine Änderung höchstens einen Test.

  2. Nur weil Sie sich eine bessere Möglichkeit ausgedacht haben, einen Test zu schreiben, würde ich nicht dorthin zurückkehren und anfangen, ihn neu zu schreiben. Dies geht auf die Personen zurück, die weiterhin dieselbe Klasse / Funktion schreiben und umschreiben, weil sie versuchen, sie zu perfektionieren. Es wird niemals perfekt sein, also mach weiter. Wenn Sie eine bessere Methode entdecken, behalten Sie diese im Hinterkopf (oder ergänzen Sie die Kommentare des Tests). Wenn Sie das nächste Mal dort sind und den unmittelbaren Vorteil eines Wechsels auf den neuen Weg sehen, ist dies die Zeit für eine Umgestaltung. Andernfalls, wenn die Funktion fertig ist und Sie fortfahren und alles funktioniert, lassen Sie es funktionieren.

  3. TDD konzentriert sich darauf, einen unmittelbaren Wert zu liefern und nicht nur sicherzustellen, dass jede Funktion testbar ist. Wenn Sie Funktionen hinzufügen, fragen Sie zunächst, was der Client benötigt. Definieren Sie dann eine Schnittstelle, um dem Client das zu geben, was er benötigt. Implementieren Sie dann alles, was zum Bestehen des Tests erforderlich ist. TDD ähnelt fast dem Testen von Anwendungsszenarien (einschließlich aller "Was-wäre-wenn"), anstatt einfach öffentliche Funktionen zu codieren und jede einzelne zu testen.

  4. Sie haben nach dem Testen des GUI-Codes gefragt. Schlagen Sie die Muster "Humble Dialog" und "MVVM" nach. Die Idee dahinter ist, dass Sie eine Reihe von "Ansichtsmodell" -Klassen erstellen, die eigentlich keine UI-spezifische Logik haben. Diese Klassen verfügen jedoch über die gesamte Geschäftslogik, die normalerweise Teil Ihrer Benutzeroberfläche ist, und diese Klassen sollten zu 100% testbar sein. Was bleibt, ist eine sehr dünne UI-Shell, und ja, normalerweise bleibt diese Shell ohne Testabdeckung, aber zu diesem Zeitpunkt sollte sie fast keine Logik haben.

  5. Wenn Sie einen großen Teil des vorhandenen Codes haben, sollten Sie, wie wenige andere vorgeschlagen haben, nicht überall Unit-Tests hinzufügen. Es wird ewig dauern und 80% der Klassen, die stabil sind und sich in naher (oder in naher) Zukunft nicht ändern werden, können Sie nicht von Unit-Tests profitieren. Für neue Arbeiten empfinde ich die Verwendung der TDD-Entwicklung mit ALLEM Code jedoch als äußerst vorteilhaft. Wenn Sie fertig sind, erhalten Sie nicht nur eine Suite mit automatisierten Tests, sondern die eigentliche Entwicklung hat auch enorme Vorteile:

    • Wenn Sie die Testbarkeit berücksichtigen, werden Sie Code schreiben, der weniger gekoppelt und modularer ist
    • Wenn Sie Ihren öffentlichen Auftrag vor allem anderen prüfen, werden Sie öffentliche Schnittstellen erhalten, die viel sauberer sind
    • Während Sie Code schreiben, dauert die Überprüfung der neuen Funktionalität Millisekunden, verglichen mit der Ausführung der gesamten Anwendung und dem Versuch, die Ausführung auf dem richtigen Weg zu erzwingen. Mein Team gibt immer noch Fehlerbehandlungscode frei, der noch nicht einmal ausgeführt wurde, nur weil es nicht die richtigen Bedingungen dafür gab. Es ist erstaunlich, wie viel Zeit wir verschwenden, wenn diese Bedingungen später in der Qualitätssicherung eintreten. Und ja, ein Großteil dieses Codes ist das, was jemand als "nicht änderungsbedürftig in der Zukunft, wenn erst einmal die Rauchprüfung durchgeführt wurde" angesehen hätte.
DXM
quelle
1

Es gibt einige Methoden, die nicht getestet werden, nämlich diese Tests. Für einige Tests, die hinzugefügt werden, nachdem der ursprüngliche Code geschrieben wurde, ist jedoch etwas zu sagen, wie z. B. Randbedingungen und andere Werte, sodass möglicherweise mehrere Tests mit einer einzelnen Methode durchgeführt werden.

Zwar können Sie Ihren Code übertesten, doch in der Regel möchte jemand jede mögliche Permutation von Eingaben testen, was nicht ganz so klingt, wie Sie es tun. Wenn Sie beispielsweise eine Methode haben, die ein Zeichen aufnimmt, schreiben Sie einen Test für jeden möglichen Wert, der eingegeben werden könnte? Das wäre der Punkt, an dem Sie zu Übertests kommen würden, IMO.

JB King
quelle
Ah, in Ordnung. Das mache ich nicht. Normalerweise denke ich nur an eine andere Situation, in der ich meine Methoden auf der ganzen Linie testen kann, nachdem ich bereits den ersten Test durchgeführt habe. Ich habe nur dafür gesorgt, dass diese "zusätzlichen" Tests es wert waren, durchgeführt zu werden, oder ob es vorbei war.
cgasser
Wenn Sie in kleinen Schritten arbeiten, können Sie in der Regel einigermaßen sicher sein, dass Ihr Test tatsächlich funktioniert. Mit anderen Worten, wenn ein Test fehlschlägt (aus dem richtigen Grund!), Wird der Test selbst getestet. Diese Stufe von "einigermaßen sicher" ist jedoch nicht so hoch wie der getestete Code.
Frank Shearar
1

Im Allgemeinen machst du es richtig.

Tests sind Code. Wenn Sie den Test verbessern können, müssen Sie ihn überarbeiten. Wenn Sie der Meinung sind, dass ein Test verbessert werden kann, ändern Sie ihn. Haben Sie keine Angst, einen Test durch einen besseren zu ersetzen.

Ich empfehle, beim Testen Ihres Codes nicht anzugeben, wie der Code das tun soll, was er tut. Tests sollten sich die Ergebnisse der Methoden ansehen. Dies wird beim Refactoring helfen. Einige Methoden müssen nicht explizit getestet werden (dh einfache Getter und Setter), da Sie diese verwenden, um die Ergebnisse anderer Tests zu überprüfen.

Schleis
quelle
Ich habe auch Tests für Getter und Setter geschrieben, also danke für diesen Tipp. Das erspart mir unnötige Arbeit.
cgasser
"Einige Methoden müssen nicht explizit getestet werden (dh einfache Getter und Setter)" - Sie haben noch nie einen Getter und Setter kopiert / eingefügt und vergessen, den Feldnamen dahinter zu ändern? Das Besondere an einfachem Code ist, dass einfache Tests erforderlich sind - wie viel Zeit sparen Sie wirklich?
pdr
Ich meine nicht, dass die Methode nicht getestet wird. Es wird nur überprüft, indem bestätigt wird, dass andere Methoden eingestellt sind, oder während der tatsächlichen Einrichtung eines Tests. Wenn der Getter oder Setter nicht ordnungsgemäß funktioniert, schlägt der Test fehl, da die Eigenschaften nicht ordnungsgemäß festgelegt wurden. Sie werden implizit kostenlos getestet.
Schleis
Getter- und Setter-Tests dauern nicht lange, daher werde ich sie wahrscheinlich auch weiterhin durchführen. Ich kopiere und füge jedoch niemals Code ein, damit ich nicht auf dieses Problem stoße.
cgasser
0

Meine Meinung zu TDD ist, dass das Tool eine Welt von Point-and-Click-Entwicklern geschaffen hat. Nur weil die Tools für jede Methode einen Teststub erstellen, müssen Sie nicht für jede Methode Tests schreiben. Einige Leute benennen TDD in BDD (Behaviour Driven Development) um, wo die Tests viel umfangreicher sind und das Verhalten der Klasse testen sollen, nicht jede fummelige Methode.

Wenn Sie Ihre Tests so entwerfen, dass die Klasse so getestet wird, wie sie verwendet werden soll, erhalten Sie einige Vorteile, insbesondere wenn Sie Tests schreiben, die etwas mehr als jede Methode erfordern, insbesondere wenn Sie die Interaktion dieser Tests testen Methoden. Ich nehme an, Sie können sich das so vorstellen, als würden Sie Tests für eine Klasse schreiben, anstatt Methoden. In jedem Fall müssen Sie noch 'Akzeptanztests' schreiben, die die Kombination von Methoden anwenden, um sicherzustellen, dass es keine Widersprüche oder Konflikte bei der gemeinsamen Verwendung gibt.

Verwechseln Sie TDD nicht mit dem Testen - das ist es nicht. TDD ist so konzipiert, dass Sie Code schreiben, um Ihre Anforderungen zu erfüllen, und nicht, um die Methoden zu testen. Es ist ein subtiler, aber wichtiger Punkt, der oft für Leute verloren geht, die blindlings Testcode für jede Methode schreiben. Sie sollten Tests schreiben, die sicherstellen, dass Ihr Code das tut, was Sie möchten, und nicht, dass der von Ihnen geschriebene Code wie vorgesehen funktioniert.

Rechts finden Sie einige gute Links zu BDD v TDD. Schau sie dir an.

gbjbaanb
quelle
0

Wenn Sie anfangen , TDD zu lernen, sollten Sie blindlings dem dogmatischen Ansatz folgen, keine einzige Codezeile zu schreiben, außer einen nicht bestandenen Test zu bestehen und nur genügend Tests zu schreiben, um zu scheitern (und dies aus dem richtigen / erwarteten Grund). .

Sobald Sie gelernt haben, worum es bei TDD geht, können Sie entscheiden, dass bestimmte Dinge keinen Test wert sind. Dies ist der gleiche Ansatz, den Sie für alles verfolgen sollten, und die japanischen Kampfkünste nennen dies " Shuhari ". (Der Link erklärt auch, wie man die Lernstufen ohne einen Lehrer durchlaufen kann, was, wie ich vermute, die meisten Menschen lernen müssen.)

Frank Shearar
quelle
0

Ich glaube, dass Sie übertesten.

Ich praktiziere seit vielen Jahren TDD, und meiner Erfahrung nach erhalten Sie bei einer effektiven Durchführung von TDD zwei Hauptvorteile:

  • Geben Sie schnelles Feedback
  • Refactoring aktivieren

Geben Sie schnelles Feedback

Insbesondere bei dynamischen Sprachen kann ich die entsprechenden Tests in weniger als einer Sekunde ausführen. Und ich habe Dateisystem-Beobachter, die diese Tests automatisch ausführen, wenn eine Quelldatei auf der Festplatte geändert wird. Somit habe ich praktisch keine Wartezeit auf Tests und weiß sofort, ob der von mir geschriebene Code wie erwartet funktioniert hat. Somit führt TDD zu einer sehr effizienten Arbeitsweise.

Refactoring aktivieren

Wenn Sie über eine gute Testsuite verfügen, können Sie sicher umgestalten, indem Sie neue Einblicke in die Gestaltung des Systems gewinnen.

Mit einer guten Testsuite können Sie die Verantwortung in Ihrem Code verschieben und trotzdem darauf vertrauen, dass der Code nach dem Verschieben wie erwartet funktioniert. Und Sie sollten in der Lage sein, dies mit kleinen Änderungen am Testcode zu tun.

Wenn Sie Tests für jede Methode in Ihrem System schreiben, besteht die Wahrscheinlichkeit, dass Sie Ihren Code nicht einfach umgestalten können. Jeder Umgestalter Ihres Codes erfordert massive Änderungen am Testcode. Und können Sie sogar sicher sein, dass der Testcode weiterhin wie erwartet funktioniert? Oder haben Sie versehentlich einen Fehler in den Testcode eingefügt, der folglich zu einem Fehler im Produktionscode führt?

Wenn Sie jedoch, wie auch in vorgeschlagen pdr Antwort , konzentrieren sich auf das Verhalten statt Methoden beim Schreiben von Tests, haben Sie Tests , die viel weniger Änderungen erforderlich werden , wenn das System Refactoring.

Oder wie Ian Cooper in dieser Präsentation sagt (ich zitierte aus dem Gedächtnis, könnte also nicht richtig zitiert sein):

Ihr Grund für das Schreiben eines neuen Tests sollte darin bestehen, ein neues Verhalten hinzuzufügen und keine neue Klasse hinzuzufügen

Pete
quelle
-2

Sie sollten jede öffentliche Methode testen .

Der Haken dabei ist, dass Sie wahrscheinlich zu viele Informationen preisgeben, wenn Ihre öffentlichen Methoden sehr klein sind. Die übliche Praxis, jede Eigenschaft als getXXX()tatsächlich verfügbar zu machen, bricht die Kapselung.

Wenn Ihre öffentlichen Methoden tatsächlich das Verhalten der Klasse sind, sollten Sie sie testen. Wenn nicht, sind sie keine guten öffentlichen Methoden.

EDIT: Die Antwort von pdr ist viel vollständiger als meine.

Chip
quelle