Was sind die Nachteile des Schreibens von Code vor dem Schreiben von Komponententests?

33

Ich habe immer die Empfehlung gesehen, zuerst Unit-Tests zu schreiben und dann mit dem Schreiben von Code zu beginnen. Ich bin jedoch der Meinung, dass es (für mich) viel komfortabler ist, in die andere Richtung zu gehen. Schreiben Sie zuerst Code und dann Unit-Tests, da wir nach dem Schreiben des eigentlichen Codes deutlich mehr Klarheit haben. Wenn ich den Code und dann die Tests schreibe, muss ich möglicherweise meinen Code ein wenig ändern, um ihn testbar zu machen, auch wenn ich mich sehr darauf konzentriere, ein testbares Design zu erstellen. Wenn ich dagegen die Tests und dann den Code schreibe, ändern sich die Tests ziemlich häufig, wenn sich der Code formt.

Was sind die Nachteile, wenn ich es anders mache - Code schreiben und dann die Komponententests?

k25
quelle
7
+1 für die Frage, warum eine bestimmte Praxis eine "beste Praxis" ist, bevor sie angenommen wird
TaylorOtwell

Antworten:

37

Rot ist die Antwort. Rot ist das, was Sie aus dem Rot-Grün-Refaktor-Zyklus von TDD erhalten, das Sie nicht bekommen können, Test-Last. Schreiben Sie zunächst einen fehlerhaften Test. Pass auf, dass es versagt. Das ist dein Rot, und es ist wichtig. Es heißt: Ich habe diese Anforderung und ich weiß, dass mein Code sie nicht erfüllt. Wenn Sie also zu Schritt 2 (grün) gehen, wissen Sie genau so sicher, dass Ihr Code diese Anforderung jetzt erfüllt. Sie wissen, dass Sie Ihre Codebasis so geändert haben, dass sie der Anforderung entspricht.

Nach dem Code entwickelte Anforderungen (Tests), die auf dem Code basieren, berauben Sie dieser Art von Gewissheit, diesem Vertrauen.

Carl Manaster
quelle
+1 - Punkt für Punkt! Danke für deine Meinung!
k25
7
Tests! = Anforderungen. Sowohl die Tests als auch der Code sollten aus den Anforderungen abgeleitet werden.
Bart van Ingen Schenau
2
@Bart van Ingen Schenau: Die Stärke von TDD ist genau das, was ARE-Anforderungen testet. Darüber hinaus sind sie ausführbare Anforderungen.
Mouviciel
1
@Bart: Unit-Tests sind oft zu detailliert für (hohe) Kundenanforderungen, aber die Idee ist definitiv gültig, insbesondere wenn wir auch Tests auf höherer Ebene in Betracht ziehen, z. Das ist die Essenz von "Agile Acceptance Testning".
Martin Wickman
3
Bei TDD geht es nicht um Tests, sondern um Spezifikationen. Tests, die in einem TDD-Ansatz erstellt wurden, sind ein Kommunikationsmittel zwischen Entwickler und Kunde, um zu vereinbaren, welches Produkt hergestellt werden soll.
Mouviciel
18

Wenn Sie den Code und dann die Tests schreiben, fällt es allzu leicht, die Tests so zu schreiben, dass der Code erfolgreich ist, anstatt die Tests zu schreiben, um sicherzustellen, dass der Code der Spezifikation entspricht.

Das heißt, es ist definitiv nicht der einzige Weg, Dinge zu tun, und es gibt keinen "besten" Weg, Software zu entwickeln. Wenn Sie viel Vorarbeit in die Entwicklung von Testfällen stecken, wissen Sie erst viel später, ob Ihre vorgeschlagene Architektur Fehler aufweist. Wenn Sie den Code jedoch zuerst entwickelt haben, werden Sie sie früher kennenlernen und mit weniger Fehlern neu entwerfen können Anstrengung.

Anon.
quelle
Ja, Sie haben Recht mit dem ersten Punkt, aber ich stelle immer sicher, dass ich das nicht tue. Wenn der Test fehlschlägt, gehe ich immer zum Code und stelle sicher, dass er richtig ist. Dann überprüfe ich, ob mein Test richtig ist, und ändere, was auch immer falsch ist. Vielen Dank für Ihre Meinung, ich werde dies in Erinnerung behalten. +1 von mir für den 1. Punkt und den letzten Punkt ...
k25
2
Aber was ist, wenn der Test erfolgreich ist? Der Test wird möglicherweise bestanden, weil er den interessierenden Code nicht tatsächlich ausübt. Dies kann unter TDD nicht wirklich passieren, da der Test anfangs fehlschlagen soll und dies auch tut. Wenn dies nicht der Fall ist, fahren Sie erst mit Schritt 2 fort, nachdem Sie den Fehler behoben haben. Es gibt also einen Fehlermodus im Test last, der im Test first nicht existiert.
Carl Manaster
@ Carl Manaster - Ja, Sie haben einen gültigen Punkt. Nachdem ich den Code geschrieben habe, kenne ich die Anforderungen genau und mein Unit-Testfall wäre (im Idealfall) richtig. Wenn mein Testfall bestanden wird, würde ich sagen, dass der Code richtig ist. Wenn der Test fehlschlägt, folge ich dem, was ich gesagt habe. Aber ich stimme zu 100% zu, dass Sie dort einen gültigen Punkt haben.
k25
@ k25: Der Punkt ist, dass Sie, wenn Ihr Testfall erfolgreich ist, immer noch nicht wissen, ob der Code richtig ist oder nicht. Der Testfall könnte falsch sein.
Anon.
@Anon. - ja du hast recht, ich werde diesen fall auch in betracht ziehen.
k25
12

Tatsächlich geht es den Leuten bei TDD darum, zu testen, obwohl sie die anderen beiden Buchstaben des Akronyms vergessen. Hier können Sie nachlesen: Bei TDD ohne T oder TDD geht es nicht um Testen .

Die Sache ist, dass ich eine Fülle anderer Dinge gelernt habe, die eng mit TDD verbunden sind. Es spielt keine Rolle, ob Sie zuerst testen: Was zählt, ist das Nachdenken über Software-Design .

Um Unit-Tests auch nur "auf die richtige Weise" schreiben zu können , dh isoliert, schnell und automatisiert, werden Sie hoffentlich feststellen, dass einige Überlegungen erforderlich sind, wie Sie Ihren Code so anordnen, dass Ihr Code einfacher wird zu testen.

Persönlich habe ich mir die SOLID-Prinzipien angeeignet, ohne zu wissen, dass so etwas geschrieben steht. Das liegt daran, dass ich beim Schreiben von Unit-Tests gezwungen war, Klassen neu zu schreiben, damit das Testen nicht zu komplex wird. Es führte zu Dingen wie:

  • Ich musste Funktionen, die entweder keinen Sinn ergaben oder sich in privaten Methoden befanden, in separate Klassen verschieben, damit ich sie separat testen konnte. (Prinzip der Einzelverantwortung).
  • Ich musste große Vererbungsstrukturen vermeiden und Implementierungen stattdessen mit Komposition erweitern (im Open-Closed-Prinzip hervorgehoben).
  • Ich musste über Vererbung klug sein, ich verwendete abstrakte Klassen, wenn ich gemeinsamen Code sah, der geteilt werden konnte, und verwendete Stubmethoden (Liskov-Substitutionsprinzip).
  • Ich musste Interfaces und abstrakte Klassen schreiben, um Klassen in Trennung testen zu können. Was Sie versehentlich dazu bringt, Scheinobjekte zu schreiben. (Prinzip der Grenzflächentrennung)
  • Da ich viele Interfaces und abstrakte Klassen geschrieben habe, begann ich, Variablen und Parameter zu deklarieren, um den allgemeinen Typ (Prinzip der Abhängigkeitsinversion) zu verwenden.

Obwohl ich nicht die ganze Zeit zuerst teste, folge ich zufällig guten OO-Prinzipien und -Praktiken, die Sie zu befolgen beginnen, nur um das Testen ein bisschen einfacher zu machen. Jetzt schreibe ich keinen Code um seiner selbst willen. Ich habe Code geschrieben, damit er leicht getestet werden kann oder was noch wichtiger ist. leicht zu pflegen .

Spoike
quelle
1
+1 für SOLID fällt Ihnen natürlich ein, wenn Sie an Software-Design denken.
ocodo
+1 (eigentlich wollte ich +10 geben, aber ich kann nicht). Genau meine Gedanken - Ihre Punkteliste war extrem gut. Das ist ein Grund, warum ich diese Frage gestellt habe. Ich hatte das Gefühl, dass die Klassen viel mehr wurden, als ich anfing, die Unit-Tests zu schreiben, nachdem ich den Code geschrieben hatte. Aber ich wollte die Vor- und Nachteile beider Seiten sehen, danke für Ihre Meinung!
k25
10

Alle anderen Antworten sind gut, aber es gibt einen Punkt, der nicht angerührt wurde. Wenn Sie den Test zuerst schreiben, wird sichergestellt, dass Tests geschrieben werden. Es ist verlockend, nach dem Schreiben des Arbeitscodes die Tests zu überspringen und sie einfach über die Benutzeroberfläche zu überprüfen. Wenn Sie die Disziplin haben, immer einen fehlerhaften Test durchzuführen, bevor Sie Code schreiben, können Sie diese Falle umgehen.

RationalGeek
quelle
4

Wenn Sie Ihre Tests zuerst schreiben, haben Sie eine weitere Chance, über Ihr Design nachzudenken, bevor dieses Design "in Stein gemeißelt" wird.

Beispielsweise könnten Sie denken, dass Sie eine Methode benötigen, die einen bestimmten Satz von Parametern akzeptiert. Und wenn Sie den Code zuerst geschrieben haben, würden Sie ihn auf diese Weise schreiben und den Test an die angegebenen Parameter anpassen. Aber wenn Sie den Test zuerst schreiben, denken Sie vielleicht: "Warten Sie eine Minute, ich möchte diesen Parameter nicht im Hauptcode verwenden, also sollte ich vielleicht die API ändern."

Anon
quelle
+1 für den ersten Punkt. Was wäre, wenn das Design mit anderen diskutiert und akzeptiert würde, ohne die Parameterebene zu erreichen?
k25
@ k25 - wenn etwas so schwer zu bedienen ist, wie es entworfen wurde, braucht es mehr Nachdenken. Manchmal - sehr selten - ist es nur eine schwere Aufgabe. Es kann jedoch häufiger auf einfachere Aufgaben reduziert werden. Ich habe keinen Link, aber entweder Gosling oder Goetz haben vor ein paar Jahren ein Interview über API-Design geführt ... das Googeln lohnt sich.
Anon
klar, danke für die hinweise, ich werde sie mir sicher ansehen ...
k25
2

Da ich viele Empfehlungen sehe, mit dem Schreiben von Tests zu beginnen und dann mit dem Codieren fortzufahren,

Dafür gibt es einen guten Grund.

Wenn du sagst "mach was sich richtig anfühlt", machen die Leute die dümmsten, verrücktesten Dinge.

Wenn Sie "Schreibtests zuerst" sagen, versuchen die Leute vielleicht, das Richtige zu tun.

Was sind die Nachteile, wenn ich es anders mache - Code schreiben und dann die Unit-Tests?

In der Regel ein mieser Test und ein Design, das überarbeitet werden muss, um testbar zu sein.

Das ist aber nur ein "Normalfall". Einige Leute entwickeln die Designs und Tests parallel. Einige Leute setzen testbaren Code ein und schreiben Tests ohne Nacharbeit.

Die "Test First" -Regel ist speziell dazu da, Menschen zu unterrichten und zu unterweisen, die überhaupt keine Ahnung haben.

In ähnlicher Weise wird uns empfohlen, immer in beide Richtungen zu schauen, bevor wir die Straße überqueren. Tatsächlich tun wir das jedoch nicht. Und es spielt keine Rolle. Ich lebe in einem Land mit Rechtslenkung und muss nur beim Überqueren nach links schauen.

Wenn ich ein Land mit Linkslenkung besuche, kann mich nur ein Blick nach links umbringen.

Die Regeln sind aus einem bestimmten Grund sehr streng festgelegt.

Was Sie tun, ist Ihr eigenes Problem.

S.Lott
quelle
2

Wenn Sie den Test zuerst schreiben, müssen Sie darüber nachdenken

  • wie man den Code testet
  • Die Schnittstelle, die der Code aufweisen muss, um testbar zu sein

Wenn Sie etwas Einfaches tun, spielt es wahrscheinlich keine Rolle, welches Sie zuerst schreiben (obwohl es gut ist, die Test-First-Gewohnheit zu pflegen), da der Test einfach und die Benutzeroberfläche offensichtlich sein wird

TDD wird jedoch zu Akzeptanztests, nicht nur zu Komponententests, und die Schnittstelle wird nicht mehr trivial.

Steven A. Lowe
quelle
1

Wenn Sie Ihre Tests nicht zuerst schreiben, führen Sie zunächst kein Test Driven Development (TDD) durch. Die Vorteile sind zahlreich und oft schwer zu glauben, bis Sie es mehrmals üben. Hier sind die Vorteile, die mir TDD gegenüber traditioneller Entwicklung gebracht hat:

  1. Ein Sicherheitsnetz aus Tests - ermöglicht es Ihnen, große Änderungen vorzunehmen, ohne die Angst zu haben, etwas unwissentlich zu beschädigen
  2. Organisches Design - das Design, mit dem ich ende, unterscheidet sich normalerweise von dem Design, das ich von Grund auf gemacht hätte, und es war schon immer besser
  3. Produktivität - auf kleine Ziele hinzuarbeiten (diesen einen Test bestehen) und es zu schaffen (alle Tests bestehen), funktioniert sehr gut für mich und hält mich motiviert. Fügen Sie ein Paar hinzu und meine Produktivität erreicht neue Höchstwerte.

Bücher: Beck, K. Testgetriebene Entwicklung am Beispiel

Gutes Beispiel: http://jamesshore.com/Blog/Lets-Play/

Mike Polen
quelle
+1 - nette Punkte (vor allem der 1.) und danke für die Links!
k25
0

Woher wissen Sie, dass ein Test einen Fehlerzustand erkennt, wenn Sie ihn schreiben? Die Antwort lautet "test the test". Wenn Sie dies tun, schreiben Sie den Test zuerst, und achten Sie darauf, dass er fehlschlägt. Erst wenn das zu testende Gerät erfolgreich codiert wurde (der in einer der anderen Antworten genannte Rot / Grün / Refaktor-Zyklus), wird der Test bestanden.

Wenn Sie zuerst den Code und dann den Test schreiben, bleibt die Frage offen, ob der Test ehrlich fehlschlagen würde.

Denken Sie daran, dass Ihre Tests die Spezifikation ausdrücken. Wenn Sie Ihre Tests überarbeiten müssen, während sich Ihr Code "formt", deutet dies darauf hin, dass sich Ihre Spezifikationen ändern. Das kann eine gute Sache sein oder auch nicht. Dies könnte bedeuten, dass Sie das Problem zunächst nicht richtig verstanden haben. Auf der anderen Seite könnte dies bedeuten, dass Sie testen, wie das Gerät seine Arbeit leistet, und nicht, was es leisten soll.

Zenilogix
quelle