Heute haben wir TDD trainiert und dabei folgende Missverständnisse festgestellt.
Die Aufgabe ist für die Eingabe "1,2" eine Rückgabesumme von 3 Zahlen. Was ich geschrieben habe (in C #) war:
numbers = input.Split(',');
return int.Parse(numbers[0]) + int.Parse(numbers[1]); //task said we have two numbers and input is correct
Aber andere Leute zogen es vor, es anders zu machen. Zunächst wurde für die Eingabe "1,2" der folgende Code hinzugefügt:
if (input == "1,2")
return 3;
Dann führten sie einen weiteren Test für die Eingabe "4,5" ein und änderten die Implementierung:
if (input == "1,2")
return 3;
else if (input == "4,5")
return 9;
Und danach sagten sie "Okay, jetzt sehen wir das Muster" und setzten das um, was ich anfangs getan hatte.
Ich denke, der zweite Ansatz passt besser zur TDD-Definition, aber ... sollten wir so streng damit umgehen? Für mich ist es in Ordnung, kleine Schritte zu überspringen und sie zu "Doppelschritten" zu kombinieren, wenn ich mir sicher bin, dass ich nichts überspringen werde. Liege ich falsch?
Aktualisieren. Ich habe einen Fehler gemacht, indem ich nicht klargestellt habe, dass es nicht der erste Test war. Es gab bereits einige Tests, so dass "return 3" eigentlich nicht der einfachste Code war, um die Anforderung zu erfüllen.
Antworten:
Schreiben Sie den einfachsten Code, mit dem die Tests bestanden werden.
Soweit ich sehen kann, hat das keiner von Ihnen getan.
Baby Schritt 1.
Test: Geben Sie für die Eingabe "1,2" die Summe der Zahlen 3 zurück
Machen Sie den Test fehlgeschlagen:
Machen Sie den Testdurchlauf:
Baby Schritt 2.
Test: Für die Eingabe "1,2" wird eine Summe von Zahlen zurückgegeben, die 3 ist
Test: Für die Eingabe "4,5" wird eine Summe von Zahlen zurückgegeben, die 9 ist
Der zweite Test schlägt fehl.
(Viel einfacher als eine Liste von if ... return)
In diesem Fall kann man sich sicherlich über die offensichtliche Implementierung streiten, aber wenn Sie davon gesprochen haben, dies ausschließlich in kleinen Schritten zu tun, dann sind dies die richtigen Schritte, IMO.
Das Argument ist, dass, wenn Sie den zweiten Test nicht schreiben, später ein heller Funke auftauchen und Ihren Code zum Lesen "umgestalten" könnte:
Und ohne beide Schritte auszuführen, wurde der zweite Test nie rot angezeigt (was bedeutet, dass der Test selbst verdächtig ist).
quelle
input.Length
ist nicht so weit hergeholt, besonders wenn die Eingabe für die Methode zufällig eine Messung aus einer Datei ist und Sie Ihre Methode absichtlich aufgerufen habenSize()
.Ich denke, der zweite Weg ist verblüffend dumm. Ich sehe den Wert darin, genügend kleine Schritte zu machen, aber diese winzigen Zygote-Schritte (ich kann sie nicht einmal Baby nennen) zu schreiben, ist nur Unsinn und Zeitverschwendung. Vor allem, wenn das ursprüngliche Problem, das Sie lösen, bereits sehr klein ist.
Ich weiß, es ist Training und es geht mehr darum, das Prinzip zu zeigen, aber ich denke, solche Beispiele tun TDD eher schlecht als gut. Wenn Sie den Wert von Babyschritten zeigen möchten, verwenden Sie zumindest ein Problem, in dem sich ein gewisser Wert befindet.
quelle
Kent Beck behandelt dies in seinem Buch Test Driven Development: By Example.
Ihr Beispiel zeigt eine ' offensichtliche Implementierung ' - Sie möchten die Summe zweier Eingabewerte zurückgeben, und dies ist ein ziemlich grundlegender Algorithmus, der erreicht werden soll. Ihr Gegenbeispiel ist "fälschen, bis Sie es schaffen" (obwohl dies ein sehr einfacher Fall ist).
Offensichtliche Implementierung kann viel komplizierter sein - aber im Grunde beginnt sie, wenn die Spezifikation für eine Methode ziemlich eng ist - zum Beispiel, wenn Sie eine URL-codierte Version einer Klasseneigenschaft zurückgeben - Sie müssen keine Zeit mit ein paar verschwenden gefälschte Kodierungen.
Eine Datenbankverbindungsroutine hingegen würde ein wenig mehr Nachdenken und Testen erfordern, sodass es keine offensichtliche Implementierung gibt (auch wenn Sie möglicherweise bereits mehrmals eine für andere Projekte geschrieben haben).
Von dem Buch:
quelle
Ich sehe es so, als würde es dem Buchstaben des Gesetzes folgen, aber nicht seinem Geist.
Ihre Babyschritte sollten sein:
Auch das Verb in der Methode ist
sum
ist keine Summe, sondern ein Test für bestimmte Eingaben.
quelle
Es erscheint mir in Ordnung, mehrere einfache Umsetzungsschritte zu einem etwas weniger einfachen zusammenzufassen - das mache ich auch die ganze Zeit. Ich denke nicht, dass man religiös werden muss, wenn man TDD jedes Mal genauestens befolgt.
OTOH dies gilt nur für wirklich triviale Schritte wie im obigen Beispiel. Für etwas Komplexeres, das ich nicht sofort im Kopf behalten kann und / oder bei dem ich mir nicht zu 110% sicher bin, gehe ich lieber einen Schritt nach dem anderen.
quelle
Wenn Sie sich zum ersten Mal mit TDD befassen, kann die Größe der Stufen ein verwirrendes Problem sein, wie diese Frage veranschaulicht. Eine Frage, die ich mir oft stellte, als ich anfing, testgetriebene Anwendungen zu schreiben, war: Hilft der Test, den ich schreibe, bei der Entwicklung meiner Anwendungen? Dies mag für manche trivial und nicht verwandt erscheinen, aber bleib einen Moment bei mir.
Wenn ich anfange, eine Bewerbung zu schreiben, beginne ich normalerweise mit einem Test. Wie wichtig dieser Test ist, hängt weitgehend von meinem Verständnis dessen ab, was ich zu tun versuche. Wenn ich denke, dass ich so ziemlich das Verhalten einer Klasse im Kopf habe, dann wird der Schritt ein großer sein. Wenn das Problem, das ich zu lösen versuche, viel weniger klar ist, besteht der Schritt möglicherweise einfach darin, dass ich weiß, dass eine Methode mit dem Namen X verwendet wird und Y zurückgegeben wird. Zu diesem Zeitpunkt verfügt die Methode nicht einmal über Parameter und Es besteht die Möglichkeit, dass sich der Name der Methode und der Rückgabetyp ändern. In beiden Fällen treiben die Tests meine Entwicklung voran. Sie erzählen mir Dinge über meine Bewerbung:
Wird diese Klasse, die ich in meinem Kopf habe, tatsächlich funktionieren?
oder
Wie zum Teufel soll ich das überhaupt machen?
Der Punkt ist, dass ich im Handumdrehen zwischen großen und kleinen Schritten wechseln kann. Wenn zum Beispiel ein großer Schritt nicht funktioniert und ich keinen offensichtlichen Weg sehe, wechsle ich zu einem kleineren Schritt. Wenn das nicht funktioniert, wechsle ich zu einem noch kleineren Schritt. Dann gibt es noch andere Techniken wie die Triangulation, wenn ich wirklich stecken bleibe.
Wenn Sie wie ich ein Entwickler und kein Tester sind, müssen Sie mit TDD nicht Tests schreiben, sondern Code schreiben. Lassen Sie sich nicht davon abhalten, viele kleine Tests zu schreiben, wenn diese Ihnen keine Vorteile bringen.
Ich hoffe, Sie haben Ihr Training mit TDD genossen. IMHO, wenn mehr Menschen testinfiziert wären, wäre die Welt ein besserer Ort :)
quelle
In einer Einführung über Unit-Tests las ich den gleichen Ansatz (Schritte, die wirklich sehr, sehr klein aussehen) und als Antwort auf die Frage "Wie klein sollten sie sein?"
Es geht darum, wie sicher Sie sind, dass die Schritte funktionieren. Sie können wirklich große Schritte machen, wenn Sie wollen. Aber versuchen Sie es einfach für einige Zeit und Sie werden eine Menge fehlgeleitetes Vertrauen in Orte finden, die Sie für selbstverständlich halten. Die Tests helfen Ihnen also dabei, ein auf Fakten basierendes Vertrauen aufzubauen.
Also, vielleicht ist dein Kollege nur ein bisschen schüchtern :)
quelle
Ist es nicht der springende Punkt, dass die Implementierung der Methode irrelevant ist, solange die Tests erfolgreich sind? Die Erweiterung der Tests schlägt im zweiten Beispiel schneller fehl, kann jedoch in beiden Fällen zum Fehlschlagen gebracht werden.
quelle
Ich bin damit einverstanden, dass die Leute sagen, dass beides nicht die einfachste Implementierung ist.
Die Methodik ist so streng, dass Sie so viele relevante Tests wie möglich schreiben müssen. Es ist in Ordnung, einen konstanten Wert für einen Testfall zurückzugeben und ihn als bestanden zu bezeichnen, da Sie gezwungen sind, zurückzugehen und anzugeben, was Sie wirklich wollen, um etwas anderes als Unsinn aus Ihrem Programm zu holen. Die Verwendung eines solchen trivialen Falls ist in mancher Hinsicht ein Schuss in den Fuß, aber das Prinzip ist, dass sich Fehler in die Lücken in Ihrer Spezifikation einschleichen, wenn Sie versuchen, "zu viel" zu tun und die Anforderung auf die einfachstmögliche Implementierung zu reduzieren, um sicherzustellen, dass a Der Test muss für jeden einzelnen Aspekt des tatsächlich gewünschten Verhaltens geschrieben werden.
quelle