it-swarm.com.de

Sind die Tests für testgetriebene Entwicklung (TDD) immer Unit-Tests?

Ich verstehe die testgetriebene Entwicklung so weit, dass Sie nur dann produktiven Code schreiben dürfen, wenn Sie einen fehlgeschlagenen (roten) Komponententest haben. Auf dieser Grundlage habe ich die Frage, ob der testgetriebene Ansatz auch auf andere Testformen angewendet werden kann.

41
user1364368

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

Normalerweise sind "Unit-Tests" 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 daran, Teile isoliert zu testen. Sie benötigen also auch andere Tests (Integration, Akzeptanz usw.). Es wird immer noch empfohlen, dieselben Prinzipien zu befolgen: Schreiben Sie einen fehlgeschlagenen Test und ändern Sie den Code, damit er funktioniert. Beachten Sie jedoch, dass sie normalerweise langsamer sind und daher die Zykluszeit Rot/Grün/Refaktor beeinflussen können.

27
David Arno

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

Nur Vertrauensprüfungen, bei denen Sie gesehen haben, dass sie bestanden und nicht bestanden wurden.

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

Einige denken, dass Unit-Tests das Kleinste abdecken, was getestet werden kann. Einige denken an alles, was schnell zu testen ist. TDD ist mehr als nur der rot-grüne Refaktorzyklus, aber dieser Teil enthält eine ganz bestimmte Reihe von Tests: Es sind nicht die Tests, die Sie idealerweise einmal ausführen, 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 Ihre Unit-Tests.

59
candied_orange

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

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

12
Doc Brown

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

Nein. Sie dürfen nur den einfachsten Code schreiben, der zum Ändern der Testnachricht möglich ist. Es sagt nichts darüber aus, welche Art von Test.

In der Tat werden Sie wahrscheinlich damit beginnen, einen nicht bestandenen (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. Anschließend schreiben Sie einen fehlgeschlagenen Funktionstest für einen Teil der Funktionalität dieses Akzeptanzkriteriums. Sie schreiben erneut den einfachsten Funktionstest, der möglicherweise fehlschlagen könnte, führen ihn aus, beobachten, wie er fehlschlägt, und überprüfen, ob er aus dem richtigen Grund fehlschlägt. Dann schreiben Sie einen fehlgeschlagenen Komponententest, den einfachsten Komponententest, der möglicherweise fehlschlagen könnte. Führen Sie ihn aus, beobachten Sie, ob er fehlschlägt, und überprüfen 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, stellen Sie sicher, dass sich die Fehlermeldung geändert hat, dass sie sich in die richtige Richtung geändert hat und dass der Code die Nachricht aus dem richtigen Grund geändert hat. (Idealerweise sollte die Fehlermeldung inzwischen verschwunden sein und der Test sollte bestanden sein. Meistens ist es jedoch besser, kleine Schritte zu unternehmen, um die Meldung zu ändern, anstatt zu versuchen, den Test auf einmal zu bestehen - das ist der Grund warum Entwickler von Test-Frameworks so viel Aufwand für ihre Fehlermeldungen betreiben!)

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

Jetzt erstellen Sie den nächsten Komponententest und wiederholen den obigen Vorgang, 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 bestanden ist. An diesem Punkt können Sie nun Refactorings im gesamten System durchführen.

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

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. Meistens brauchen Sie weniger. Wenn Ihre Funktionalität klein ist und Ihre Funktionstests schnell sind, können Sie ohne (oder mit weniger Komponententests) auskommen. Oft benötigen Sie nur Abnahmetests und Unit-Tests. Oder Ihre Akzeptanzkriterien sind so feinkörnig, dass Ihre Akzeptanztests sind Funktionstests.

Kent Beck sagt, wenn er einen schnellen, kleinen und fokussierten Funktionstest hat, schreibt er zuerst die Unit-Tests, lässt die Unit-Tests den Code steuern und löscht dann (einige) Unit-Tests 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, 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: all Ihre Entwicklung wird von Tests getrieben. Die Tests steuern nicht nur den Code, den Sie schreiben, sondern auch was Code zum Schreiben, welcher Code als nächstes geschrieben werden soll. 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 meinen . Es besteht aus einer Reihe von Regeln (basierend auf Onkel Bob Martins Drei TDD-Regeln , aber viel strenger), die Sie strikt befolgen müssen und die Sie dazu bringen sollen, TDD stärker anzuwenden rigoros. 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 Richtung einer Lösung zu weisen scheint
  2. Sehen Sie, wie es fehlschlägt; Kompilierungsfehler gelten als Fehler
  3. Machen Sie den Test aus (1) bestanden, indem Sie den geringsten Implementierungscode schreiben, den Sie in der Testmethode können.
  4. Refactor, um Duplikate zu entfernen, und ansonsten nach Bedarf, um das Design zu verbessern. Seien Sie streng bei der Verwendung dieser Schritte:
    1. Sie möchten eine neue Methode - warten Sie bis zur Umgestaltung, und erstellen Sie dann… neue (nicht testweise) Methoden, indem Sie eine dieser Methoden ausführen, und auf keine andere Weise :
      • bevorzugt: Methode nach Implementierungscode extrahieren, der gemäß (3) erstellt wurde, um eine neue Methode in der Testklasse zu erstellen, oder
      • wenn Sie müssen: Implementierungscode gemäß (3) in eine vorhandene Implementierungsmethode verschieben
    2. Sie möchten eine neue Klasse - warten Sie bis zur Refactoring-Zeit und erstellen Sie dann… Nicht-Test-Klassen, um ein Ziel für eine Verschiebungsmethode und aus keinem anderen Grund bereitzustellen
    3. füllen Sie Implementierungsklassen mit Methoden, indem Sie die Verschiebungsmethode 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 zu machen (obwohl nichts Sie davon abhält, es auszuprobieren). Sie können sich frustrierend anfühlen, weil es manchmal so aussieht, als ob Sie Tausende winziger kleiner Schritte machen, ohne wirklich Fortschritte zu machen.

8
Jörg W Mittag

TDD ist keineswegs auf das beschränkt, was die traditionelle Software-Test-Community als "Unit-Test" bezeichnet. Dieses sehr häufige Missverständnis ist das Ergebnis von Kent Becks unglücklicher Überlastung des Begriffs "Einheit" bei der Beschreibung seiner TDD-Praxis. Was er mit "Unit Test" meinte, war ein Test, der isoliert abläuft. Es ist nicht abhängig von anderen Tests. Jeder Test muss den Status einrichten, den er benötigt, und anschließend eine Bereinigung durchführen. In diesem Sinne ist ein Komponententest im TDD-Sinne eine Einheit. Es ist in sich geschlossen. Es kann von selbst oder zusammen mit jedem anderen Komponententest in beliebiger Reihenfolge ausgeführt werden.

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

Kent Beck beschreibt in Kapitel 32 - Mastering TDD, was er unter „Unit Test“ versteht

2

Ich habe weder Bücher darüber gelesen, noch folge ich ständig den "Standard" -DDD-Praktiken, aber in meinen Augen ist der Hauptpunkt der TDD-Philosophie, dem ich vollkommen zustimme, dass Sie zuerst den Erfolg definieren müssen . Dies ist auf jeder Ebene des Designs wichtig, von "Was ist das Ziel dieses Projekts?" zu "Was sollen die Ein- und Ausgänge dieser kleinen Methode sein?"

Es gibt viele Möglichkeiten, diese Definition von Erfolg zu verwirklichen. Eine nützliche Methode, insbesondere für Methoden auf niedriger Ebene mit möglicherweise vielen Edge-Fällen, besteht darin, Tests in Code zu schreiben. Für einige Abstraktionsebenen kann es nützlich sein, nur eine kurze Notiz über das Ziel des Moduls oder was auch immer aufzuschreiben oder sich selbst im Kopf zu überprüfen (oder einen Mitarbeiter zu fragen), um sicherzustellen, dass alles Sinn macht und sich in einem befindet logischer Ort. Manchmal ist es hilfreich, einen Integrationstest im Code zu beschreiben (und natürlich hilft dies bei der Automatisierung), und manchmal ist es hilfreich, nur einen angemessenen schnellen Testplan zu definieren, mit dem Sie sicherstellen können, dass alle Systeme auf Ihre Weise zusammenarbeiten erwarten.

Unabhängig von den spezifischen Techniken oder Tools, die Sie verwenden, ist meiner Meinung nach der Schlüssel zur Abkehr von der TDD-Philosophie, dass die Definition des Erfolgs zuerst erfolgt. Andernfalls werfen Sie den Pfeil und malen das Bullauge überall dort herum, wo es gerade gelandet ist.

1
user101289

Im Vortrag Testgetriebene Entwicklung: Dies ist nicht das, was wir gemeint haben Steve Freeman zeigt die folgende Folie des TDD-Gesamtbilds (siehe Bild unten, Antwort). Dies beinhaltet einen Schritt "Schreiben eines fehlgeschlagenen End-to-End-Tests" , gefolgt von "Schreiben eines fehlgeschlagenen Komponententests". (Zum Vergrößern klicken, oben rechts)

Also nein in TDD sind die Tests nicht immer Unit-Tests.

Und ja, Sie können (und sollten vielleicht) 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 erklärt die Erfahrung von LMAX, die zeigt, dass End-to-End-Tests eine große und wertvolle Rolle spielen können .

(enter image description here