Wann schreiben Sie den "echten" Code in TDD?

johnny 08/19/2017. 11 answers, 20.464 views
tdd

Alle Beispiele, die ich in Trainingsvideos gelesen und gesehen habe, haben einfache Beispiele. Aber was ich nicht sehe, wie ich den "richtigen" Code mache, nachdem ich grün geworden bin. Ist das der "Refactor" -Teil?

Wenn ich ein ziemlich komplexes Objekt mit einer komplexen Methode habe, schreibe ich meinen Test und das Minimum, um es zu bestehen (nachdem es zuerst fehlschlägt, Rot). Wann gehe ich zurück und schreibe den richtigen Code? Und wie viel echten Code schreibe ich, bevor ich es erneut teste? Ich nehme an, dass Letzteres mehr Intuition ist.

Edit: Danke an alle, die geantwortet haben. All deine Antworten haben mir sehr geholfen. Es scheint verschiedene Ideen zu geben, was ich gefragt oder verwirrt habe, und vielleicht gibt es das, aber was ich gefragt habe, war, dass ich einen Antrag für den Bau einer Schule habe.

In meinem Entwurf habe ich eine Architektur, mit der ich beginnen möchte, User Stories, und so weiter. Von hier aus nehme ich diese User Stories und erstelle einen Test, um die User Story zu testen. Der Benutzer sagt: Wir haben Leute, die sich für die Schule einschreiben und Anmeldegebühren zahlen. Also denke ich an einen Weg, um das zu scheitern. Dabei entwerfe ich eine Testklasse für Klasse X (vielleicht Student), die fehlschlägt. Ich erstelle dann die Klasse "Student". Vielleicht "Schule", weiß ich nicht.

Auf jeden Fall zwingt mich das TD Design dazu, die Geschichte zu durchdenken. Wenn ich einen Test zum Scheitern bringen kann, weiß ich, warum das scheitert, aber das setzt voraus, dass ich es bestehen lassen kann. Es geht um das Design.

Ich vergleiche das mit dem Gedanken an Rekursion. Rekursion ist kein hartes Konzept. Es mag schwieriger sein, es tatsächlich in deinem Kopf zu verfolgen, aber in Wirklichkeit ist das Schwierigste, zu wissen, wann die Rekursion "bricht", wann aufzuhören ist (meine Meinung natürlich). Also muss ich darüber nachdenken, was aufhört die Rekursion zuerst. Es ist nur eine unvollkommene Analogie und nimmt an, dass jede rekursive Iteration ein "Durchlauf" ist. Wiederum nur eine Meinung.

In Umsetzung, Die Schule ist schwerer zu sehen. Numerische und Bankbücher sind "einfach" in dem Sinne, dass Sie einfache Arithmetik verwenden können. Ich kann a + b sehen und 0 zurückgeben usw. Im Falle eines Systems von Menschen muss ich mir überlegen, wie ich das implement . Ich habe das Konzept des Fail, Pass, Refactor (hauptsächlich wegen des Studiums und dieser Frage).

Was ich nicht weiß, basiert meiner Meinung nach auf mangelnder Erfahrung. Ich weiß nicht, wie ich einen neuen Studenten nicht unterschreiben kann. Ich weiß nicht, wie man jemanden scheitert, der einen Nachnamen eintippt und in einer Datenbank gespeichert wird. Ich weiß, wie man eine + 1 für einfache Mathe macht, aber mit Entitäten wie einer Person, weiß ich nicht, ob ich nur teste, um zu sehen, ob ich eine Datenbank eindeutige ID oder etwas anderes zurückbekomme, wenn jemand einen Namen in eine Datenbank oder beides oder keines.

Oder, vielleicht zeigt das, dass ich immer noch verwirrt bin.

5 Comments
187 hobbs 07/25/2017
Nach dem TDD gehen die Leute für die Nacht nach Hause.
14 Goyo 07/25/2017
Warum denkst du, dass der Code, den du geschrieben hast, nicht echt ist?
2 johnny 07/26/2017
@ RubberDuck Mehr als die anderen Antworten taten. Ich bin mir sicher, dass ich mich bald darauf beziehe. Es ist immer noch irgendwie fremd, aber ich werde es nicht aufgeben. Was du gesagt hast, ergab Sinn. Ich versuche nur, es in meinem Kontext oder einer normalen Geschäftsanwendung sinnvoll zu machen. Vielleicht ein Inventar-System oder ähnliches. Ich muss darüber nachdenken. Ich bin dankbar für Ihre Zeit. Vielen Dank.
1 Edmund Reed 07/26/2017
Die Antworten treffen bereits den Nagel auf den Kopf, aber solange alle Ihre Tests bestehen und Sie keine neuen Tests / Funktionen benötigen, kann davon ausgegangen werden, dass der Code, den Sie haben, fertig ist, Bar-Linting.
3 Borjab 07/26/2017
Es gibt eine Annahme in der Frage, die in "Ich habe ein ziemlich komplexes Objekt mit einer komplexen Methode" problematisch sein kann. In TDD schreiben Sie zuerst Ihre Tests, also beginnen Sie mit einem ziemlich einfachen Code. Dies wird Sie zwingen, eine testfreundliche Struktur zu programmieren, die modular sein muss. So komplexes Verhalten wird durch die Kombination einfacher Objekte erzeugt. Wenn Sie mit einem ziemlich komplexen Objekt oder einer ziemlich komplizierten Methode enden, dann ist das ein Refactor

11 Answers


RubberDuck 07/27/2017.

Wenn ich ein ziemlich komplexes Objekt mit einer komplexen Methode habe, schreibe ich meinen Test und das Minimum, um es zu bestehen (nachdem es zuerst fehlschlägt, Rot). Wann gehe ich zurück und schreibe den richtigen Code? Und wie viel echten Code schreibe ich, bevor ich es erneut teste? Ich nehme an, dass Letzteres mehr Intuition ist.

Sie gehen nicht zurück und schreiben "echten Code". Es ist alles echter Code. Was Sie tun, ist, zurückzugehen und einen weiteren Test hinzuzufügen, der Sie forces , Ihren Code zu change , damit der neue Test bestanden wird.

Wie viel Code schreibst du vor dem Test? Keiner. Sie schreiben zero Code ohne einen fehlgeschlagenen Test, der Sie forces , mehr Code zu schreiben.

Beachten Sie das Muster?

Lassen Sie uns (ein anderes) einfaches Beispiel durchgehen, in der Hoffnung, dass es hilft.

 Assert.Equal("1", FizzBuzz(1)); 

Einfach peazy.

 public String FizzBuzz(int n) {
    return 1.ToString();
} 

Nicht was du echten Code nennen würdest, oder? Lassen Sie uns einen Test hinzufügen, der eine Änderung erzwingt.

 Assert.Equal("2", FizzBuzz(2)); 

Wir könnten etwas dummes tun, if n == 1 , aber wir gehen zur gesunden Lösung über.

 public String FizzBuzz(int n) {
    return n.ToString();
} 

Cool. Dies funktioniert für alle Nicht-FizzBuzz-Nummern. Was ist die nächste Eingabe, die dazu führt, dass sich der Produktionscode ändert?

 Assert.Equal("Fizz", FizzBuzz(3));

public String FizzBuzz(int n) {
    if (n == 3)
        return "Fizz";
    return n.ToString();
} 

Und wieder. Schreibe einen Test, der noch nicht bestanden wird.

 Assert.Equal("Fizz", FizzBuzz(6));

public String FizzBuzz(int n) {
    if (n % 3 == 0)
        return "Fizz";
    return n.ToString();
} 

Und wir haben jetzt alle Vielfachen von Drei abgedeckt (das sind auch keine Vielfachen von Fünf, wir werden es notieren und zurückkommen).

Wir haben noch keinen Test für "Buzz" geschrieben, also lasst uns das schreiben.

 Assert.Equal("Buzz", FizzBuzz(5));

public String FizzBuzz(int n) {
    if (n % 3 == 0)
        return "Fizz";
    if (n == 5)
        return "Buzz"
    return n.ToString();
} 

Und wieder wissen wir, dass wir noch einen weiteren Fall behandeln müssen.

 Assert.Equal("Buzz", FizzBuzz(10));

public String FizzBuzz(int n) {
    if (n % 3 == 0)
        return "Fizz";
    if (n % 5 == 0)
        return "Buzz"
    return n.ToString();
} 

Und jetzt können wir alle Vielfachen von 5 behandeln, die nicht auch Vielfache von 3 sind.

Bis zu diesem Punkt haben wir den Refactoring-Schritt ignoriert, aber ich sehe einige Duplizierungen. Lass uns das jetzt aufräumen.

 private bool isDivisibleBy(int divisor, int input) {
    return (input % divisor == 0);
}

public String FizzBuzz(int n) {
    if (isDivisibleBy(3, n))
        return "Fizz";
    if (isDivisibleBy(5, n))
        return "Buzz"
    return n.ToString();
} 

Cool. Jetzt haben wir die Duplizierung entfernt und eine gut benannte Funktion erstellt. Was ist der nächste Test, den wir schreiben können, der uns zwingt, den Code zu ändern? Nun, wir haben den Fall vermieden, wo die Zahl durch 3 und 5 teilbar ist. Lassen Sie uns jetzt schreiben.

 Assert.Equal("FizzBuzz", FizzBuzz(15));

public String FizzBuzz(int n) {
    if (isDivisibleBy(3, n) && isDivisibleBy(5, n))
        return "FizzBuzz";
    if (isDivisibleBy(3, n))
        return "Fizz";
    if (isDivisibleBy(5, n))
        return "Buzz"
    return n.ToString();
} 

Die Tests bestehen, aber wir haben mehr Doppelarbeit. Wir haben Optionen, aber ich werde "Lokale Variable extrahieren" ein paar Mal anwenden, so dass wir refactoring statt neu zu schreiben.

 public String FizzBuzz(int n) {

    var isDivisibleBy3 = isDivisibleBy(3, n);
    var isDivisibleBy5 = isDivisibleBy(5, n);

    if ( isDivisibleBy3 && isDivisibleBy5 )
        return "FizzBuzz";
    if ( isDivisibleBy3 )
        return "Fizz";
    if ( isDivisibleBy5 )
        return "Buzz"
    return n.ToString();
} 

Und wir haben alle vernünftigen Eingaben behandelt, aber was ist mit unreasonable Eingaben? Was passiert, wenn wir 0 oder ein Negativ passieren? Schreiben Sie diese Testfälle.

 public String FizzBuzz(int n) {

    if (n < 1)
        throw new InvalidArgException("n must be >= 1);

    var isDivisibleBy3 = isDivisibleBy(3, n);
    var isDivisibleBy5 = isDivisibleBy(5, n);

    if ( isDivisibleBy3 && isDivisibleBy5 )
        return "FizzBuzz";
    if ( isDivisibleBy3 )
        return "Fizz";
    if ( isDivisibleBy5 )
        return "Buzz"
    return n.ToString();
} 

Sieht das schon nach "echtem Code" aus? Wichtiger noch, wann hörte es auf, "unwirklicher Code" zu sein und zu "real" zu werden? Darüber muss man nachdenken ...

Also konnte ich dies einfach dadurch erreichen, dass ich nach einem Test suchte, von dem ich wusste, dass er bei jedem Schritt nicht bestehen würde, aber ich hatte viel Übung. Wenn ich bei der Arbeit bin, sind die Dinge nicht so einfach und ich weiß vielleicht nicht immer, welcher Test eine Veränderung erzwingt. Manchmal schreibe ich einen Test und bin überrascht zu sehen, dass er bereits bestanden hat! Ich empfehle dringend, dass Sie sich angewöhnen, eine "Testliste" zu erstellen, bevor Sie beginnen. Diese Testliste sollte alle "interessanten" Eingaben enthalten, die Sie sich vorstellen können. Sie können sie möglicherweise nicht alle verwenden, und Sie werden wahrscheinlich Fälle hinzufügen, während Sie fortfahren, aber diese Liste dient als Roadmap. Meine Testliste für FizzBuzz würde ungefähr so ​​aussehen.

  • Negativ
  • Null
  • Ein
  • Zwei
  • Drei
  • Vier
  • Fünf
  • Sechs (nicht triviales Vielfaches von 3)
  • Neun (3 Quadrat)
  • Zehn (nicht triviales Vielfaches von 5)
  • 15 (mehrere von 3 und 5)
  • 30 (nicht triviales Vielfaches von 3 & 5)
5 comments
3 maple_shaft♦ 07/27/2017
Kommentare sind nicht für längere Diskussionen; Diese Konversation wurde in den Chat verschoben .
40 GManNickG 07/27/2017
Es sei denn, ich missverstehe diese Antwort vollständig: "Wir könnten etwas Dummes tun, wie wenn n == 1, aber wir werden zur vernünftigen Lösung übergehen." - Die ganze Sache war albern. Wenn Sie wissen, dass Sie eine Funktion haben, die <spec> ausführt, schreiben Sie Tests für <spec> und überspringen Sie den Teil, in dem Sie Versionen schreiben, die offensichtlich <spec> nicht erfüllen. Wenn Sie einen Fehler in <spec> finden, dann ist es sicher: Schreiben Sie zuerst einen Test, um zu überprüfen, ob Sie ihn vor dem Fix ausführen können und beobachten Sie die Testdurchläufe nach dem Fix. Aber es ist nicht nötig, all diese Zwischenschritte zu fälschen.
15 user3791372 07/28/2017
Die Kommentare, die auf die Hauptfehler in dieser Antwort und TDD im Allgemeinen hinweisen, wurden in den Chat verschoben. Wenn Sie TDD verwenden möchten, lesen Sie bitte den 'Chat'. Leider sind die "Qualitäts" -Kommentare nun in einer Menge von Chat versteckt, damit zukünftige Schüler sie lesen können.
nbro 07/28/2017
Ich würde den Inhalt dieser "Testliste" präzisieren, wenn Sie diese Antwort verbessern möchten. Ich würde explizit von "Grenzwerten" und "Klassenpartitionierung" sprechen.
2 hvd 07/30/2017
@GManNickG Ich glaube, der Punkt ist, die richtige Menge an Tests zu bekommen. Wenn man die Tests vorher schreibt, kann man leicht übersehen, welche speziellen Fälle getestet werden müssen, was dazu führt, dass Situationen in den Tests nicht angemessen behandelt werden oder dass im Wesentlichen die gleiche Situation in den Tests unnötig oft abgedeckt wird. Wenn du das ohne diese Zwischenschritte machen kannst, großartig! Nicht jeder kann das, aber es braucht Übung.

GenericJon 07/24/2017.

Der "echte" Code ist der Code, den Sie schreiben, um Ihren Test bestanden zu haben. Really . So einfach ist das.

Wenn Leute darüber reden, das Nötigste zu schreiben, um den Test grün zu machen, bedeutet das nur, dass Ihr echter Code dem YAGNI-Prinzip folgen sollte.

Die Idee des Refactor-Schritts besteht darin, das, was Sie geschrieben haben, aufzuräumen, sobald Sie zufrieden sind, dass es die Anforderungen erfüllt.

Solange die Tests, die Sie schreiben, tatsächlich Ihre Produktanforderungen umfassen, ist der Code vollständig. Denken Sie darüber nach, wenn alle Ihre geschäftlichen Anforderungen einen Test haben und alle diese Tests grün sind, was gibt es mehr zu schreiben? (Okay, im wirklichen Leben neigen wir nicht dazu, eine vollständige Testabdeckung zu haben, aber die Theorie ist vernünftig.)

5 comments
44 Derek Elkins 07/24/2017
Komponententests können Ihre Produktanforderungen nicht einmal für relativ triviale Anforderungen umfassen. Im besten Fall samplen sie den Eingabe-Ausgabe-Raum und die Idee ist, dass Sie (korrekt) auf den gesamten Eingabe-Ausgabe-Bereich verallgemeinern. Natürlich könnte Ihr Code nur ein großer switch mit einem Fall für jeden Komponententest sein, der alle Tests bestehen und für andere Eingaben fehlschlagen würde.
8 Taemyr 07/25/2017
@DerekElkins TDD schreibt fehlgeschlagene Tests vor. Nicht fehlgeschlagene Unit Tests.
6 jonrsharpe 07/25/2017
@DerekElkins deshalb schreiben Sie nicht nur Komponententests, und auch, warum es eine allgemeine Annahme gibt, dass Sie versuchen, etwas zu machen, nicht nur es zu fälschen!
35 Derek Elkins 07/25/2017
@jonrsharpe Durch diese Logik würde ich niemals triviale Implementierungen schreiben. Im Beispiel von FizzBuzz in der Antwort von RubberDuck (die nur Komponententests verwendet) wird die erste Implementierung eindeutig "nur gefälscht". Mein Verständnis der Frage ist genau diese Dichotomie zwischen dem Schreiben von Code, von dem Sie wissen, dass er unvollständig ist, und Code, von dem Sie wirklich glauben, dass er die Anforderung, den "echten Code", implementieren wird. Mein "großer switch " war als logisches Extrem gedacht, "das Nötigste zu schreiben, um die Tests grün zu machen". Ich betrachte die Frage des OP wie: Wo in TDD ist das Prinzip, das diesen großen switch vermeidet?
2 Luaan 07/25/2017
@GenericJon Das ist ein bisschen zu optimistisch in meiner Erfahrung :) Zum einen gibt es Menschen, die sich gedankenlos wiederholende Arbeit genießen. Sie werden mit einer riesigen Switch-Aussage glücklicher sein als mit einer "komplizierten Entscheidungsfindung". Und um ihren Job zu verlieren, brauchen sie entweder jemanden, der sie auffordert (und sie haben bessere Beweise dafür, dass sie die Chancen / das Geld des Unternehmens verlieren!), Oder sie tun außergewöhnlich schlecht. Nachdem ich die Wartung vieler solcher Projekte übernommen habe, kann ich sagen, dass es für sehr naiven Code einfach ist, Jahrzehnte zu halten, solange es den Kunden glücklich macht (und bezahlt).

Carl Raymond 07/24/2017.

Die kurze Antwort ist, dass der "echte Code" der Code ist, der den Test bestanden hat. Wenn Sie Ihren Test mit etwas anderem als echtem Code bestehen lassen können, fügen Sie weitere Tests hinzu!

Ich stimme zu, dass viele Tutorials zu TDD einfach sind. Das wirkt gegen sie. Ein zu einfacher Test für eine Methode, die beispielsweise 3 + 8 berechnet, hat wirklich keine andere Wahl, als 3 + 8 zu berechnen und das Ergebnis zu vergleichen. Dadurch sieht es so aus, als würden Sie einfach überall Code duplizieren, und dieser Test ist sinnlos und fehleranfällig.

Wenn Sie gut testen können, werden Sie darüber informiert, wie Sie Ihre Anwendung strukturieren und wie Sie Ihren Code schreiben. Wenn Sie Schwierigkeiten haben, vernünftige, hilfreiche Tests zu machen, sollten Sie Ihr Design wahrscheinlich ein wenig überdenken. Ein gut durchdachtes System ist einfach zu testen - sinnvolle Tests sind einfach zu denken und zu implementieren.

Wenn Sie zuerst Ihre Tests schreiben, sehen Sie, wie sie ausfallen, und schreiben Sie dann den Code, der sie passieren lässt. Das ist eine Disziplin, um sicherzustellen, dass Ihr gesamter Code über entsprechende Tests verfügt. Ich befolge diese Regel nicht sklavisch, wenn ich kodiere; oft schreibe ich Tests nach der Tat. Aber zuerst Tests zu machen hilft dir, ehrlich zu bleiben. Mit etwas Erfahrung werden Sie feststellen, wenn Sie sich in eine Ecke einschreiben, selbst wenn Sie nicht zuerst Tests schreiben.

4 comments
6 Steve Jessop 07/26/2017
Persönlich wäre der Test, den ich schreiben würde, assertEqual(plus(3,8), 11) , nicht assertEqual(plus(3,8), my_test_implementation_of_addition(3,8)) . Für komplexere Fälle suchen Sie immer nach einem Mittel, das Ergebnis korrekt zu prüfen, other than das korrekte Ergebnis im Test dynamisch berechnen und die Gleichheit überprüfen.
Steve Jessop 07/26/2017
Also für eine wirklich alberne Art, es für dieses Beispiel zu tun, könnten Sie beweisen, dass plus(3,8) das korrekte Ergebnis durch Subtrahieren von 3 von ihm, Subtrahieren von 8 davon und Überprüfen des Ergebnisses gegen 0 zurückgegeben hat. Das ist so offensichtlich äquivalent zu assertEqual(plus(3,8), 3+8) , um ein bisschen absurd zu sein, aber wenn der getestete Code etwas Komplizierteres als nur eine Ganzzahl erzeugt, dann ist es oft das Ergebnis und die Überprüfung jedes Teils auf Korrektheit der richtige Ansatz. Alternativ kann etwas wie for (i=0, j=10; i < 10; ++i, ++j) assertEqual(plus(i, 10), j)
Steve Jessop 07/26/2017
... weil das die große Angst vermeidet, nämlich dass wir beim Schreiben des Tests den gleichen Fehler beim Thema "Wie 10 hinzuzufügen" machen, den wir im Live-Code gemacht haben. Daher vermeidet der Test sorgfältig das Schreiben von Code, der zu irgendetwas 10 addiert, in dem Test, dass plus() den Dingen 10 hinzufügen kann. Wir verlassen uns natürlich immer noch auf die programmiererüberprüften Initial Loop-Werte.
3 Warbo 07/28/2017
Ich möchte nur darauf hinweisen, dass selbst wenn Sie Tests nach der Tat schreiben, es immer noch eine gute Idee ist, sie beim Scheitern zu beobachten. Finde einen Teil des Codes, der für das, woran du gerade arbeitest, entscheidend ist, twee ein wenig (zB ersetze ein + durch ein - oder was auch immer), führe die Tests durch und beobachte, wie sie ausfallen, mache die Änderung rückgängig und beobachte sie. Viele Male habe ich das gemacht, der Test versagt nicht wirklich, macht es schlimmer als nutzlos: es testet nicht nur nichts, es gibt mir ein falsches Vertrauen, dass etwas getestet wird!

Victor Cejudo 07/25/2017.

Manchmal können einige Beispiele über TDD irreführend sein. Wie andere Leute bereits erwähnt haben, ist der Code, den Sie schreiben, um Tests zu bestehen, der echte Code.

Aber denken Sie nicht, dass der echte Code magisch erscheint - das ist falsch. Sie müssen besser verstehen, was Sie erreichen möchten, und dann müssen Sie den Test entsprechend auswählen, angefangen bei den einfachsten Fällen und Fällen.

Zum Beispiel, wenn Sie einen Lexer schreiben müssen, beginnen Sie mit einer leeren Zeichenfolge, dann mit einer Reihe von Leerzeichen, dann einer Zahl, dann mit einer Zahl umgeben von Leerzeichen, dann eine falsche Zahl, usw. Diese kleinen Transformationen führen Sie zu der richtige Algorithmus, aber Sie springen nicht vom einfachsten Fall in einen hochkomplexen Fall, der dummerweise gewählt wird, um den richtigen Code zu erhalten.

Bob Martin erklärt es hier perfekt.


CandiedOrange 07/25/2017.

Der Refactor-Teil ist sauber, wenn du müde bist und nach Hause gehen willst.

Wenn Sie eine Funktion hinzufügen, ändert sich der Refaktorteil vor dem nächsten Test. Sie refaktorieren den Code, um Platz für die neue Funktion zu schaffen. Sie tun dies, wenn Sie know was dieses neue Feature sein wird. Nicht wenn du es dir nur vorstellst.

Dies kann so einfach sein wie das Umbenennen von GreetImpl in GreetWorld bevor Sie eine GreetMom Klasse erstellen (nachdem Sie einen Test hinzugefügt haben), um ein Feature hinzuzufügen, das "Hi Mom" ​​druckt.


graeme 07/27/2017.

Aber der echte Code würde in der Refaktorstufe der TDD-Phase erscheinen. Dh der Code, der Teil der endgültigen Version sein sollte.

Tests sollten jedes Mal ausgeführt werden, wenn Sie eine Änderung vornehmen.

Das Motto des TDD-Lebenszyklus wäre: RED GREEN REFACTOR

RED : Schreiben Sie die Tests

GREEN : Machen Sie einen ehrlichen Versuch, Funktionscode zu erhalten, der Tests so schnell wie möglich besteht: Duplikatcode, obskure Variablen-Hacks der höchsten Ordnung usw.

REFACTOR : Bereinigen Sie den Code, benennen Sie die Variablen richtig. DRY den Code.

5 comments
5 mcottle 07/25/2017
Ich weiß, was Sie über die "Green" -Phase sagen, aber es bedeutet, dass Hard-Wiring-Rückgabewerte, die die Tests bestehen, angemessen sind. Meiner Erfahrung nach sollte "Green" ein ehrlicher Versuch sein, den Arbeitscode so zu gestalten, dass er die Anforderung erfüllt, er ist vielleicht nicht perfekt, aber er sollte so vollständig und "shippbar" sein, wie der Entwickler es in einem ersten Durchgang schaffen kann. Das Refactoring wird wahrscheinlich am besten später durchgeführt, nachdem Sie mehr Entwicklung gemacht haben und die Probleme mit dem ersten Durchlauf deutlicher werden und Möglichkeiten zum DRY entstehen.
graeme 07/25/2017
@mcottle Ich betrachte diese alle Teil der gleichen Aufgabe. mach es fertig, dann mach es sauber. Weitere Refactorings sollten im Laufe der Zeit als Teil anderer Aufgaben stattfinden.
1 Bryan Boettcher 07/25/2017
@mcottle: Sie könnten überrascht sein, wie viele Implementierungen eines Get-Only-Repositorys fest codierte Werte in der Codebasis sein können. :)
6 Kaz 07/25/2017
Warum sollte ich jemals Mist-Code schreiben und es aufräumen, wenn ich netten, Produktionsqualitäts-Code fast so schnell wie ich tippen kann? :)
1 Kaz 07/27/2017
@TimothyTruckle Was dauert 50 Minuten, um die einfachste mögliche Änderung zu finden, aber nur 5, um die zweite möglichst einfache Änderung zu finden? Gehen wir mit dem zweiteinfachsten oder suchen wir am einfachsten?

Timothy Truckle 07/27/2017.

Wann schreiben Sie den "echten" Code in TDD?

In der red Phase write Sie Code.

In der refactoring Phase ist das primäre Ziel das delete Code.

In der red Phase tun Sie alles, um den Test as quick as possible und at any cost durchzuführen. Sie ignorieren völlig, was Sie jemals über gute Codierpraktiken oder Designmuster gehört haben. Nur der Test ist grün.

In der refactoring räumst du das Chaos auf, das du gerade gemacht hast. Jetzt sehen Sie zuerst, ob die Änderung, die Sie gerade vorgenommen haben, die oberste in der Liste der Transformationsprioritäten ist. Wenn es Codeverdopplungen gibt, können Sie diese am ehesten entfernen, indem Sie ein Entwurfsmuster anwenden.

Schließlich verbessern Sie die Lesbarkeit, indem Sie Bezeichner umbenennen und magic numbers und / oder literale Zeichenfolgen in Konstanten extrahieren.


Es ist kein Rot-Refactor, es ist Rot-Grün-Refactor. - Rob Kinyon

Danke, dass Sie darauf hingewiesen haben.

Es ist also die green Phase, in der Sie den real code schreiben

In der red Phase schreibst du die executable specification ...

2 comments
Rob Kinyon 07/27/2017
Es ist kein Rot-Refactor, es ist Rot-Grün-Refactor. Die "rote" ist, nehmen Sie Ihre Testsuite von grün (alle Tests bestehen) bis rot (ein Test fehlschlägt). Das "grüne" ist, wo Sie schlampig Ihre Test-Suite von rot (ein Test fehlschlägt) zu grün (alle Tests bestanden). Der "Refactor" ist, wo Sie Ihren Code nehmen und es hübsch machen, während alle Tests bestehen bleiben.
Timothy Truckle 07/27/2017
@RobKinyon Danke, aktualisiert die Antwort.

Robert Andrzejuk 07/27/2017.

Du schreibst Real Code die ganze Zeit.

Bei jedem Schritt schreiben Sie Code, um die Bedingungen zu erfüllen, die Ihr Code für zukünftige Anrufer Ihres Codes erfüllen wird (das könnte Sie sein oder nicht ...).

Sie denken, Sie schreiben nicht nützlichen ( real ) Code, weil Sie es in einem Moment umgestalten könnten.

Code-Refactoring ist der Prozess der Umstrukturierung bestehender Computer-Code-Änderung des Factoring-ohne sein externes Verhalten zu ändern.

Dies bedeutet, dass die Bedingungen, die der Code erfüllt, unverändert bleiben, auch wenn Sie den Code ändern. Und die Überprüfungen ( tests ), die Sie zur Überprüfung Ihres Codes implementiert haben, sind bereits vorhanden, um zu überprüfen, ob Ihre Änderungen etwas geändert haben. Also ist der Code, den du die ganze Zeit geschrieben hast, genau anders drin.

Ein weiterer Grund Sie denken vielleicht, dass es sich nicht um echten Code handelt, Sie tun Beispiele, bei denen das Endprogramm bereits von Ihnen vorhergesehen werden kann. Dies ist sehr gut, da es zeigt, dass Sie Wissen über die domain Sie programmieren.
Aber Programmierer sind oft in einer new , ihnen unknown domain . Sie wissen nicht, was das Endergebnis sein wird und TDD ist eine technique , um Programme Schritt für Schritt zu schreiben, unser knowledge über die Funktionsweise dieses Systems zu dokumentieren und zu überprüfen, dass unser Code auf diese Weise funktioniert.

Als ich The Book (*) auf TDD gelesen habe, war für mich das wichtigste Feature, das herausragte, die: TODO-Liste. Es hat mir gezeigt, dass TDD auch eine Technik ist, um Entwicklern zu helfen, sich auf eine Sache nach der anderen zu konzentrieren. Also das ist auch eine Antwort auf Ihre Frage ab How much Real code to write ? Ich würde genug Code sagen, um sich auf eine Sache zu konzentrieren.

(*) "Test Driven Development: By Example" von Kent Beck

1 comments
2 Robert Andrzejuk 07/27/2017
"Test Driven Development: Mit Beispiel" von Kent Beck

Zenilogix 07/31/2017.

Sie schreiben keinen Code, damit Ihre Tests fehlschlagen.

Sie schreiben Ihre Tests, um zu definieren, wie der Erfolg aussehen soll. Dies sollte zunächst einmal fehlschlagen, weil Sie den noch nicht bestandenen Code noch nicht geschrieben haben.

Der Hauptpunkt beim Schreiben von anfänglich fehlgeschlagenen Tests ist, zwei Dinge zu tun:

  1. Bedecken Sie alle Fälle - alle nominellen Fälle, alle Randfälle, usw.
  2. Validiere deine Tests. Wenn Sie sie immer nur sehen, wie können Sie sicher sein, dass sie einen Fehler zuverlässig melden, wenn einer auftritt?

Der Punkt hinter Rot-Grün-Refactor ist, dass das Schreiben der richtigen Tests Ihnen das Vertrauen gibt zu wissen, dass der Code, den Sie geschrieben haben, um die Tests zu bestehen, korrekt ist und Sie mit der Gewissheit umgestalten können, dass Ihre Tests Sie sofort informieren werden etwas bricht, so dass Sie sofort zurückgehen und es reparieren können.

In meiner eigenen Erfahrung (C # /. NET) ist reiner Test-First ein bisschen ein unerreichbares Ideal, weil man einen Aufruf an eine Methode, die noch nicht existiert, nicht kompilieren kann. Bei "test first" geht es also zunächst darum, Interfaces und Stubbing-Implementierungen zu kodieren und dann Tests gegen die Stubs zu schreiben (was zunächst fehlschlägt), bis die Stubs richtig ausgearbeitet sind. Ich schreibe nie "fehlerhaften Code", ich baue nur aus Stubs.


Zan Lynx 07/27/2017.

Ich denke, Sie können zwischen Komponententests und Integrationstests verwirrt sein. Ich glaube, es kann auch Akzeptanztests geben, aber das hängt von Ihrem Prozess ab.

Sobald Sie alle kleinen "Einheiten" getestet haben, testen Sie sie alle zusammengebaut oder "integriert". Das ist normalerweise ein ganzes Programm oder eine Bibliothek.

In Code, den ich geschrieben habe, testet die Integration eine Bibliothek mit verschiedenen Testprogrammen, die Daten lesen und in die Bibliothek einspeisen, und dann die Ergebnisse überprüfen. Dann mache ich es mit Fäden. Dann mache ich es mit Fäden und Gabel () in der Mitte. Dann starte ich es und töte -9 nach 2 Sekunden, dann starte ich es und überprüfe seinen Wiederherstellungsmodus. Ich fuzz es. Ich foltere es auf alle möglichen Arten.

All das wird auch getestet, aber ich habe kein hübsches rot / grünes Display für die Ergebnisse. Es ist entweder erfolgreich, oder ich durchsuche ein paar tausend Zeilen Fehlercode, um herauszufinden, warum.

Dort testen Sie den "echten Code".

Und ich habe gerade darüber nachgedacht, aber vielleicht weißt du nicht, wann du Schreibgerätestests machen sollst. Sie haben Schreibgerätestests abgeschlossen, wenn Ihre Tests alle von Ihnen festgelegten Aufgaben ausführen. Manchmal können Sie dies unter allen Fehlerbehandlungs- und Edge-Fällen aus dem Auge verlieren, also möchten Sie vielleicht eine nette Testgruppe von Happy-Path-Tests erstellen, die einfach durch die Spezifikationen gehen.

1 comments
Peter Mortensen 07/27/2017
(es ist = besitzergreifend, es ist = "es ist" oder "es hat". Siehe zum Beispiel How to Use Its and It's .)

user3791372 07/27/2017.

Als Antwort auf den Titel der Frage: "Wann schreibst du den" echten "Code in TDD?" Lautet die Antwort: "fast nie" oder "sehr langsam".

Du hörst dich an wie ein Schüler, also werde ich antworten, als würde ich einen Schüler beraten.

Du wirst viele "Theorien" und "Techniken" lernen. Sie eignen sich hervorragend, um die Zeit mit überteuerten Kursen zu verbringen, aber von geringem Nutzen für Sie, die Sie in der Hälfte der Zeit nicht in einem Buch lesen konnten.

Die Aufgabe eines Coders besteht ausschließlich darin, Code zu erstellen. Code, der wirklich gut funktioniert. Deshalb planen Sie, der Programmierer den Code in Ihrem Kopf, auf Papier, in einer geeigneten Anwendung, usw., und Sie planen, mögliche Fehler / Lücken im Voraus durch logisches und laterales Denken vor dem Codieren zu umgehen.

Aber Sie müssen wissen, wie Sie Ihre Anwendung brechen können, um anständigen Code zu entwickeln. Wenn Sie beispielsweise Little Bobby Table (xkcd 327) nicht kennen, werden Sie Ihre Eingaben wahrscheinlich nicht bereinigen, bevor Sie mit der Datenbank arbeiten, sodass Sie Ihre Daten nicht mit diesem Konzept sichern könnten.

TDD ist nur ein Workflow, der entwickelt wurde, um die Fehler in Ihrem Code zu minimieren, indem er vor dem Codieren Ihrer Anwendung Tests erstellt, was schiefgehen könnte, da das Codieren exponentiell schwieriger wird, je mehr Code Sie einführen und Sie Fehler vergessen, an die Sie einmal gedacht haben. Sobald Sie denken, dass Sie Ihre Anwendung beendet haben, führen Sie die Tests und den Boom durch, hoffentlich werden Fehler bei Ihren Tests festgestellt.

TDD ist nicht - wie manche Leute glauben - einen Test schreiben, ihn mit minimalem Code passieren lassen, einen anderen Test schreiben, diese Passage mit minimalem Code bekommen, etc. Stattdessen ist es ein Weg, Ihnen zu helfen, sicher zu programmieren. Dieses Ideal des kontinuierlichen Refactoring-Codes, um es mit Tests arbeiten zu lassen, ist idiotisch, aber es ist ein nettes Konzept unter den Studenten, weil es ihnen ein gutes Gefühl gibt, wenn sie eine neue Funktion hinzufügen und sie noch lernen, wie man programmiert ...

Bitte fallen Sie nicht in diese Falle und sehen Sie Ihre Rolle des Codierens für das, was es ist - die Aufgabe eines Codierers besteht einzig darin, Code zu produzieren. Code, der wirklich gut funktioniert. Nun denken Sie daran, dass Sie als professioneller Programmierer auf der Uhr stehen werden, und es Ihrem Client egal ist, ob Sie 100.000 Assertionen oder 0 schreiben. Sie wollen nur Code, der funktioniert. Wirklich gut, tatsächlich.

5 comments
3 johnny 07/25/2017
Ich bin nicht einmal in der Nähe eines Studenten, aber ich lese und versuche, gute Techniken anzuwenden und professionell zu sein. In diesem Sinne bin ich ein "Student". Ich stelle nur grundlegende Fragen, weil ich so bin. Ich möchte genau wissen, warum ich mache, was ich tue. Der Kern der Sache. Wenn ich das nicht verstehe, mag ich es nicht und fange an, Fragen zu stellen. Ich muss wissen warum, wenn ich es benutzen werde. TDD scheint in mancher Hinsicht intuitiv gut zu sein, wie zu wissen, was man braucht, um etwas zu erschaffen und zu denken, aber die Implementierung war schwer zu verstehen. Ich denke, ich habe jetzt ein besseres Verständnis.
4 Sean Burton 07/27/2017
Das sind die Regeln von TDD. Sie können Code schreiben, wie Sie wollen, aber wenn Sie diesen drei Regeln nicht folgen, tun Sie nicht TDD.
2 user3791372 07/27/2017
"Regeln" einer Person? TDD ist ein Vorschlag, der Ihnen hilft, Code zu schreiben, keine Religion. Es ist traurig zu sehen, dass so viele Menschen sich so an eine Idee halten. Auch der Ursprung von TDD ist umstritten.
2 Alex 07/28/2017
@ user3791372 TDD ist ein sehr strenger und klar definierter Prozess. Selbst wenn viele denken, dass das nur gemein ist "Mach ein paar Tests, wenn du programmierst", ist es das nicht. Lassen Sie uns versuchen, die Begriffe hier nicht zu verwechseln, diese Frage betrifft die TDD des Prozesses, nicht das allgemeine Testen.

Related questions

Hot questions

Language

Popular Tags