Sind die Tests für Test Driven Development (TDD) immer Unit-Tests?

41

Ich verstehe die testgetriebene Entwicklung so weit, dass Sie nur dann produktiven Code schreiben dürfen, wenn Sie einen fehlerhaften (roten) Unit-Test haben. Darauf aufbauend habe ich die Frage, ob der testgetriebene Ansatz auch auf andere Testformen anwendbar ist.

user1364368
quelle
6
Es ist nicht ungewöhnlich, mehr als eine unterschiedliche Ebene von Rot / Grün / Refaktor zu verwenden, die ineinander verschachtelt sind. Beispielsweise können Sie Rot / Grün / Refaktor verfolgen, während Sie Akzeptanz- / Verhaltenstests schreiben, wobei die "grüne" Phase des Akzeptanztests selbst mehrere Rot / Grün / Refaktor-Iterationen von Komponententests enthält.
Sean Burton
1
Der Titel stimmt nicht mit dem Inhalt der Frage überein. Titel "Sind Tests immer Komponententests " (Antwort: Nein, es kann andere Arten von Tests als Komponententests geben), der Inhalt fragt "Müssen Sie den Test zuerst schreiben?".
AnoE
@AnoE Der erste Satz des Inhalts ist nur eine einleitende Aussage. Der zweite Satz fragt nicht, ob der Test zuerst geschrieben werden muss, sondern ob der TDD-Ansatz für andere Testmethoden als TDD verwendet werden kann.
user1364368
@ user1364368, zögern Sie nicht, die Frage ein wenig umzuformulieren. Zumindest war ich verwirrt darüber, was Ihre Absicht in der ersten Lesung ist, und die Frage mit den meisten Stimmen, während Sie beide Sätze ansprechen, fängt auch mit der ersten prominent an.
AnoE
@AnoE Ich habe den Anfang des zweiten Satzes geändert, um zu verdeutlichen, was die eigentliche Frage ist.
user1364368

Antworten:

27

Alles, was TDD von Ihnen verlangt, ist, dass Sie einen fehlerhaften Test schreiben und dann Ihren Code so ändern, dass er bestanden wird.

Typischerweise sind "Komponententests" klein und schnell und testen einen Teil Ihres Codes isoliert. Da sie schnell sind, ist auch die Rot / Grün / Refaktor-Schleife schnell. Sie leiden jedoch nur unter dem isolierten Testen von Teilen. Sie benötigen also auch andere Tests (Integration, Akzeptanz usw.). Es ist immer noch eine gute Praxis, die gleichen Prinzipien zu befolgen: Schreiben Sie einen fehlerhaften Test und ändern Sie den Code, damit er funktioniert. Beachten Sie jedoch, dass sie in der Regel langsamer sind, was sich auf die Zykluszeit von Rot / Grün / Refaktor auswirken kann.

David Arno
quelle
59

Der rot-grüne Refaktorzyklus basiert auf einem sehr soliden Prinzip:

Nur Vertrauenswürdigkeitstests, bei denen Sie sowohl Bestanden als auch Nichtbestanden festgestellt haben.

Ja, das funktioniert auch mit automatisierten Integrationstests. Auch manuelle Tests. Heck, es funktioniert auf Autobatterietestern. So testen Sie den Test.

Einige denken, Unit-Tests decken das Kleinste ab, was getestet werden kann. Manche denken an alles, was schnell zu testen ist. TDD ist mehr als nur der Rot-Grün-Refaktor-Zyklus, aber dieser Teil hat eine Reihe von Tests: Es sind nicht die Tests, die Sie idealerweise einmal ausführen werden, bevor Sie eine Sammlung von Änderungen einreichen. Es sind die Tests, die Sie jedes Mal ausführen, wenn Sie Änderungen vornehmen. Für mich sind das deine Unit-Tests.

kandierte_orange
quelle
1
Dies ist auch ein Grund, warum negative Tests wichtig sind, wenn geprüft werden soll, ob ein Fehler auftritt: Sie möchten sicherstellen, dass alles andere funktioniert hat, sodass zwei Tests (einer den genau erwarteten Fehler, der andere den Fehler nicht) nebeneinander liegen ich hilft , das Vertrauen zu erhöhen , dass in Zukunft dieser rot / grün Zustand wird fortgesetzt.
Matthieu M.
12

Ich frage mich jedoch, ob der testgetriebene Ansatz auch auf andere Testformen angewendet werden kann.

Ja, und ein bekannter Ansatz, der dies tut, ist die verhaltensorientierte Entwicklung . Die Tests, die aus der formalen Spezifikation in BDD generiert werden, können als "Komponententests" bezeichnet werden. Sie sind jedoch in der Regel nicht so niedrig wie bei echten TDD. Sie passen wahrscheinlich besser zum Begriff "Abnahmetests".

Doc Brown
quelle
8

Ich verstehe die testgetriebene Entwicklung so weit, dass Sie nur dann produktiven Code schreiben dürfen, wenn Sie einen fehlerhaften (roten) Unit-Test haben.

Nein. Sie dürfen nur den einfachsten Code schreiben, um die Meldung des Tests zu ändern. Es sagt nichts über welche Art von Test.

In der Tat werden Sie wahrscheinlich damit beginnen, einen fehlerhaften (roten) Abnahmetest für ein Abnahmekriterium zu schreiben. Genauer gesagt, Sie schreiben den einfachsten Abnahmetest, der möglicherweise fehlschlagen könnte. Anschließend führen Sie den Test aus, beobachten, wie er fehlschlägt, und stellen sicher, dass er aus dem richtigen Grund fehlschlägt. Dann schreiben Sie einen fehlgeschlagenen Funktionstest für einen Teil der Funktionalität dieses Akzeptanzkriteriums. Wieder schreiben Sie den einfachsten Funktionstest, der möglicherweise fehlschlägt. Führen Sie ihn aus, beobachten Sie, wie er fehlschlägt, und überprüfen Sie, ob er aus dem richtigen Grund fehlschlägt. Dann schreiben Sie einen fehlgeschlagenen Komponententest, den einfachsten Komponententest, der möglicherweise fehlschlägt. Führen Sie ihn aus, und beobachten Sie, ob er aus dem richtigen Grund fehlschlägt.

Jetzt schreiben Sie den einfachsten Produktionscode, der möglicherweise die Fehlermeldung ändern könnte. Führen Sie den Test erneut aus, und stellen Sie sicher, dass sich die Fehlermeldung geändert hat, dass sich die Richtung geändert hat und dass der Code die Nachricht aus dem richtigen Grund geändert hat. (Im Idealfall sollte die Fehlermeldung inzwischen verschwunden sein und der Test sollte bestanden werden. Meistens ist es jedoch besser, kleine Schritte zu unternehmen, um die Meldung zu ändern, anstatt zu versuchen, den Test in einem Durchgang zu bestehen. Dies ist der Grund warum Entwickler von Test-Frameworks so viel Aufwand mit ihren Fehlermeldungen betreiben!)

Sobald Sie den Komponententest bestanden haben, überarbeiten Sie Ihren Produktionscode unter dem Schutz Ihrer Tests. (Beachten Sie, dass zu diesem Zeitpunkt der Abnahmetest und der Funktionstest immer noch fehlschlagen, aber das ist in Ordnung, da Sie nur einzelne Einheiten umgestalten, die durch Einheitentests abgedeckt werden.)

Jetzt erstellen Sie den nächsten Komponententest und wiederholen diesen, bis auch der Funktionstest bestanden ist. Unter dem Schutz des Funktionstests können Sie jetzt Refactorings über mehrere Einheiten hinweg durchführen.

Dieser mittlere Zyklus wird nun wiederholt, bis der Abnahmetest erfolgreich abgeschlossen wurde. Anschließend können Sie Refactorings im gesamten System durchführen.

Nun wählen Sie das nächste Akzeptanzkriterium und der äußere Zyklus beginnt erneut.

Kent Beck, der "Entdecker" von TDD (er mag den Begriff "Erfinder" nicht, er sagt, die Leute haben das die ganze Zeit gemacht, er hat ihm nur einen Namen gegeben und ein Buch darüber geschrieben), verwendet eine Analogie aus der Fotografie und nennt dies "Vergrößern und Verkleinern".

Hinweis: Sie benötigen nicht immer drei Teststufen. Vielleicht brauchst du manchmal mehr. Oft brauchen Sie weniger. Wenn Ihre Funktionen klein sind und Ihre Funktionstests schnell sind, können Sie ohne (oder mit weniger Komponententests) auskommen. Häufig benötigen Sie nur Abnahmetests und Unit-Tests. Oder Ihre Akzeptanzkriterien sind so feinkörnig, dass es sich bei Ihren Akzeptanztests um Funktionstests handelt.

Kent Beck sagt, wenn er einen schnellen, kleinen und gezielten Funktionstest hat, schreibt er zuerst die Komponententests, lässt die Komponententests den Code fahren und löscht dann (einige) die Komponententests erneut, die den Code abdecken, der auch ist abgedeckt durch den schnellen Funktionstest. Denken Sie daran: Testcode ist auch Code, der gewartet und überarbeitet werden muss. Je weniger es gibt, desto besser!

Ich frage mich jedoch, ob der testgetriebene Ansatz auch auf andere Testformen angewendet werden kann.

Sie wenden TDD nicht wirklich auf Tests an. Sie wenden es auf Ihren gesamten Entwicklungsprozess an. Das ist es, was der "getriebene" Teil von Test- Driven- Development bedeutet: Ihre gesamte Entwicklung wird von Tests getrieben. Die Tests nicht nur den Code fahren Sie schreiben, sie auch fahren , was Code zu schreiben, neben welchem Code zu schreiben. Sie bestimmen Ihr Design. Sie sagen dir, wann du fertig bist. Sie sagen dir, woran du als nächstes arbeiten sollst. Sie informieren Sie über Designfehler in Ihrem Code (wenn Tests schwer zu schreiben sind).

Keith Braithwaite hat eine Übung erstellt, die er TDD nennt, als ob Sie es gemeint hätten . Es besteht aus einer Reihe von Regeln (basierend auf den drei TDD-Regeln von Onkel Bob Martin , aber viel strenger), die Sie genau befolgen müssen und die Sie dazu bringen sollen, TDD strenger anzuwenden. Es funktioniert am besten mit der Paarprogrammierung (damit Ihr Paar sicherstellen kann, dass Sie nicht gegen die Regeln verstoßen) und einem Lehrer.

Die Regeln sind:

  1. Schreiben Sie genau einen neuen Test, den kleinsten Test, der in die Richtung einer Lösung weist
  2. Sieh es scheitern; Kompilierungsfehler gelten als Fehler
  3. Führen Sie den Test aus (1) durch, indem Sie den niedrigsten Implementierungscode schreiben, den Sie in der Testmethode haben können .
  4. Refaktor zum Entfernen von Duplikaten und ansonsten nach Bedarf zum Verbessern des Designs. Sei streng mit diesen Zügen:
    1. Sie möchten eine neue Methode - warten Sie bis zum Refactoring und… erstellen Sie neue (nicht testbezogene) Methoden, indem Sie eine der folgenden Aktionen ausführen, und auf keine andere Weise:
      • bevorzugt: Extrahieren Sie die Methode anhand des gemäß (3) erstellten Implementierungscodes, um eine neue Methode in der Testklasse zu erstellen, oder
      • wenn Sie müssen: Verschieben Sie den Implementierungscode gemäß (3) in eine vorhandene Implementierungsmethode
    2. Sie möchten eine neue Klasse - warten Sie bis zum Refactoring, und erstellen Sie dann Nicht-Test-Klassen, um ein Ziel für eine Verschiebungsmethode bereitzustellen, und ohne weiteren Grund
    3. Füllen Sie Implementierungsklassen mit Methoden, indem Sie Move Method ausführen, und auf keine andere Weise

Diese Regeln sind für die Ausübung von TDD gedacht. Sie sind nicht dafür gedacht, TDD tatsächlich in der Produktion auszuführen (obwohl nichts Sie davon abhält, es auszuprobieren). Sie können sich frustrierend fühlen, weil es manchmal so scheint, als ob Sie Tausende winziger kleiner Schritte machen, ohne wirklich Fortschritte zu machen.

Jörg W. Mittag
quelle
2

TDD ist keineswegs auf das beschränkt, was die traditionelle Software Testing-Community "Unit Testing" nennt. Dieses sehr häufige Missverständnis ist das Ergebnis von Kent Becks unglücklicher Überfrachtung des Begriffs "Einheit" bei der Beschreibung seiner TDD-Praxis. Was er mit "Komponententest" meinte, war ein Test, der isoliert ablief. Es ist nicht abhängig von anderen Tests. Bei jedem Test muss der erforderliche Status festgelegt und anschließend eine Bereinigung durchgeführt werden. In diesem Sinne ist ein Einheitentest im TDD-Sinne eine Einheit. Es ist in sich geschlossen. Es kann von selbst oder zusammen mit einem anderen Komponententest in beliebiger Reihenfolge ausgeführt werden.

Literaturhinweis : "Test Driven Development By Example" von Kent Beck

Kent Beck beschreibt, was er unter „Komponententest“ versteht, in Kapitel 32 - Beherrschen von TDD

Jason Desrosiers
quelle
1

Ich habe keine Bücher darüber gelesen und folge auch nicht ständig den "normalen" TDD-Praktiken, aber in meinen Augen besteht der Hauptpunkt der TDD-Philosophie, der ich voll und ganz zustimme, darin, dass Sie zuerst den Erfolg definieren müssen . Dies ist auf jeder Designebene wichtig, ab "Was ist das Ziel dieses Projekts?" zu "Was sollen die Ein- und Ausgänge dieser kleinen Methode sein?"

Es gibt viele Möglichkeiten, um diese Definition von Erfolg zu verwirklichen. Besonders für Low-Level-Methoden mit potenziell vielen Randfällen ist es nützlich, Tests in Code zu schreiben. Für einige Abstraktionsebenen kann es hilfreich sein, einfach eine kurze Notiz über das Ziel des Moduls oder was auch immer zu schreiben oder sich selbst zu überprüfen (oder einen Mitarbeiter zu fragen), ob alles Sinn macht und sich in einem befindet logischer Ort. Manchmal ist es hilfreich, einen Integrationstest in Code zu beschreiben (und das hilft natürlich, ihn zu automatisieren), und manchmal ist es hilfreich, nur einen angemessenen Schnelltestplan zu definieren, mit dem Sie sicherstellen können, dass alle Systeme auf Ihre Art und Weise zusammenarbeiten erwarten.

Unabhängig von den spezifischen Techniken oder Tools, die Sie verwenden, ist meiner Meinung nach das Wichtigste, was Sie von der TDD-Philosophie abbringen sollten, dass der Erfolg zuerst definiert wird. Ansonsten wirfst du den Pfeil und malst dann das Bullauge überall herum, wo es zufällig gelandet ist.


quelle
1

Im Vortrag Test-Driven Development: Dies ist nicht das, was wir gemeint haben. Steve Freeman zeigt die folgende Folie des TDD-Gesamtüberblicks (siehe Bild unten, Antwort). Dies beinhaltet einen Schritt "Schreiben eines fehlgeschlagenen End-to-End-Tests" , gefolgt von "Schreiben eines fehlgeschlagenen Unit-Tests". (Klicken zum Vergrößern, oben rechts)

Nein, in TDD sind die Tests nicht immer Komponententests.

Und ja, Sie können (und sollten) mit einem übergeordneten End-to-End-Test beginnen, der fehlschlägt, bevor Sie Ihren ersten Komponententest schreiben. Dieser Test beschreibt das Verhalten, das Sie erreichen möchten. Dies erzeugt eine Abdeckung auf mehr Ebenen der Testpyramide . Adrian Sutton erläutert die Erfahrungen von LMAX, die zeigen, dass End-to-End-Tests eine große und wertvolle Rolle spielen können .

Bildbeschreibung hier eingeben

Niels van Reijmersdal
quelle
-1

Nein, es kann aus einem einfachen praktischen Grund nicht auf andere Arten von Tests angewendet werden: Die Ausführung anderer Arten von Tests dauert zu lange.

Ein typischer TDD-Zyklus ist: Fehler beim Schreiben, Implementieren, Refactor-Code. Zwischenschritte sind das Erstellen und Ausführen von Tests, und diese müssen blitzschnell sein. Wenn dies nicht der Fall ist, werden die Schritte übersprungen, und Sie führen keine TDD mehr durch.

BЈовић
quelle
1
Dies ist falsch: Je nach Programm und Test (und Sprache) können End-to-End-Integrationstests problemlos in weniger als 3 Sekunden ausgeführt werden. Es ist durchaus möglich, eine vollständige End-to-End-Testsuite in sehr kurzer Zeit auszuführen, selbst wenn sie gut konzipiert ist. Also "kann nicht" ist ziemlich stark.
Jonathan Cast
@jcast Ich habe noch nie etwas gesehen, das so schnell ist. Meine Funktionstests für mein vorheriges Projekt haben 30 Sekunden gedauert, und das geht schnell. Integration noch länger. In meinem Fall ergab sonst nichts Sinn. Außerdem sind Unit-Tests die schnellsten Tests aller Art - daher ist es sinnvoll, sie zu verwenden.
BЈовић