Die Leute sagen, dass "über TDD zu sprechen kaum funktioniert, wenn Sie jemanden von TDD überzeugen wollen, zeigen Sie ihm Ergebnisse". Ohne TDD bekomme ich jedoch bereits großartige Ergebnisse. Wenn ich zeige, dass Menschen, die TDD verwenden, keine guten Ergebnisse erzielen, kann ich nicht überzeugen. Ich möchte sehen, dass Menschen, die sowohl TDD als auch Nicht-TDD schreiben, mit TDD bessere Ergebnisse erzielen.
Trotz alledem bin ich daran interessiert, TDD auszuprobieren. Ich bin jedoch nicht davon überzeugt, dass ich daraus etwas gewinnen werde. Wenn es sich als nützlich erweist, werde ich versuchen, es an den Rest meines Teams weiterzuleiten.
Meine Hauptfrage lautet: Würde TDD einen Zweck für Code erfüllen, wenn ich die Korrektheit des Codes bereits nachweisen kann?
Offensichtlich ist keiner eine Silberkugel. Ihr Beweis ist möglicherweise falsch, weil Sie ein Detail übersehen haben und Ihr Test möglicherweise keinen Fehler erkennt, auf den Sie nicht getestet haben. Am Ende sind wir Menschen, niemand kann für immer 100% fehlerfreien Code erstellen. Wir können uns nur bemühen, so nah wie möglich zu kommen.
Würde TDD jedoch tatsächlich Zeit für Code sparen, dessen Richtigkeit nachgewiesen wurde? dh Code, bei dem in der Zustandsmaschine, auf der der Code ausgeführt wird, alle gültigen möglichen Zustände und ihre Bereiche vom Entwickler erkannt werden, alle berücksichtigt werden und der Code in einer Fehlerprüfung im Whitelist-Stil entworfen wird, an die jede Ausnahme übergeben wird ein oberer Handler, um sicherzustellen, dass keine unerwarteten Lecks auftreten -> ohne dass dem Client eine (innerhalb des Grundes) relevante Nachricht angezeigt und Protokollbenachrichtigungen an einen Administrator gesendet werden.
Antworten mit Beispielen aus der Praxis wären besser.
Einige Klarstellungen:
Bei dieser Frage geht es nicht darum, ob Sie die Korrektheit des Codes nachweisen können oder nicht. Nehmen wir standardmäßig an, dass nicht der gesamte Code innerhalb eines angemessenen Zeitraums als korrekt erwiesen werden kann, sondern dass einige Codeteile korrekt sein können. Zum Beispiel ist es sehr einfach, die Richtigkeit eines FizzBuzz-Moduls nachzuweisen. Für einen Cloud-basierten Datensynchronisierungsdienst nicht sehr einfach.
Innerhalb dieser Grenzen stellt die Frage Folgendes: Beginnen Sie mit der Annahme, dass eine Codebasis in zwei Teile unterteilt ist: [I] Teile, die sich als richtig erwiesen haben [II] Teile, die sich nicht als richtig erwiesen haben, aber manuell auf ihre Funktion getestet wurden.
Ich möchte TDD-Praktiken auf diese Codebasis anwenden, die sie bisher nicht hatte. Die Frage lautet wie folgt: Sollte TDD auf jedes einzelne Modul angewendet werden, oder würde es ausreichen, sie nur auf Module anzuwenden, die sich als nicht korrekt erwiesen haben?
"Bewährt richtig" bedeutet, dass Sie dieses Modul als vollständig funktional betrachten können, dh es basiert nicht auf einem globalen oder äußeren Zustand außerhalb von sich selbst und verfügt über eine vollständig eigene API für E / A, der andere Module folgen müssen, die mit ihm interagieren . Es ist nicht möglich, dieses Modul durch Ändern des Codes außerhalb des Moduls zu "beschädigen". Im schlimmsten Fall können Sie ihn missbrauchen und formatierte Fehlermeldungen erhalten.
Natürlich gibt es in jeder Regel Ausnahmen. Compiler-Fehler in neuen Compiler-Versionen können zu Fehlern in diesem Modul führen. Dieselben Fehler können jedoch auch bei Tests auftreten, die sie getestet haben, und zu einem falschen Sicherheitsgefühl bei Tests führen, die nicht mehr wie beabsichtigt funktionieren. Das Fazit ist, dass Tests keine magische Lösung sind, sondern eine weitere Schutzschicht. In dieser Frage wird die Frage erörtert, ob diese Schutzschicht im konkreten Fall eines Moduls, das sich als richtig erwiesen hat, die Mühe wert ist (nehmen Sie an, dass es war in der Tat).
Antworten:
Ja.
Beweise sind in Ordnung, wenn sie verfügbar sind, aber selbst zu den besten Zeiten beweisen sie nur, dass ein einzelnes Codebit wie erwartet funktioniert (für alle Eingaben - Berücksichtigung von Unterbrechungen während eines Vorgangs - wie wäre es, wenn der Speicher knapp wird? ? Festplattenfehler? Netzwerkfehler?).
Was passiert, wenn es sich ändert?
Tests sind großartig, da sie als impliziter Vertrag darüber dienen, was der Code tun soll. Sie bieten ein Gerüst, damit Ihr neuer Praktikant mit einem gewissen Maß an Vertrauen Änderungen vornehmen kann. Alles über schnelle, klare Ergebnisse: bestanden oder nicht bestanden.
Und ehrlich gesagt kann ich einen Praktikanten coachen, um in wenigen Monaten brauchbare Unit-Tests zu schreiben. Ich bezweifle, dass irgendjemand in meinem Team (ich selbst eingeschlossen) Beweise erstellen kann, die alles garantieren, was für nicht trivialen Code von Bedeutung ist. geschweige denn schnell und genau.
quelle
For large & rapidly changing projects
Je anfälliger für Änderungen, desto notwendiger sind die Tests, da ein sich ändernder Code aufgrund neuer Fehler oder unerwarteter Verhaltensweisen viel häufiger fehlschlägt als Code, der sich kaum ändert. Es ist eine Frage der Wahrscheinlichkeit. Auch wenn es sich nicht oft ändert, kann das während der Entwicklung gewonnene Wissen nach einer Weile verloren gehen oder in Vergessenheit geraten. Tests sind auch materialisiertes Wissen, das die Lernkurve erheblich verkürzen kann. Sind Codierungstests zeitaufwändig? Ja. Verteuert es das Projekt? Nein, auf lange Sicht billiger machen .Wir wissen es nicht. Wir können Ihre Frage nicht beantworten.
Während Sie viel Zeit damit verbringen, diesen Prozess zu erklären, der jetzt zu jedermanns Zufriedenheit zu funktionieren scheint, erzählen Sie uns nur einen kleinen Teil dessen, was tatsächlich passiert.
Nach meiner Erfahrung ist das, was Sie beschreiben, eine extreme Seltenheit, und ich bin skeptisch, dass es tatsächlich Ihr Prozess und Ihre Herangehensweise an das Codieren ist, die tatsächlich zu einer geringen Fehleranzahl in Ihren Anwendungen führen. Möglicherweise gibt es viele andere Faktoren, die Ihre Anwendungen beeinflussen, und Sie sagen uns nichts über diese Faktoren.
Wir wissen also nicht, ob TDD Ihnen helfen wird oder nicht, obwohl Sie Ihre genaue Entwicklungsumgebung und -kultur nicht kennen. Und wir können Tage damit verbringen, darüber zu diskutieren und zu streiten.
Wir können Ihnen nur eine Empfehlung geben: Probieren Sie es aus. Experiment. Lern es. Ich weiß, dass Sie versuchen, sich mit geringstem Aufwand zu entscheiden, aber das ist nicht möglich. Wenn Sie wirklich wissen möchten, ob TDD in Ihrem Kontext funktioniert, können Sie dies nur herausfinden, indem Sie tatsächlich TDD ausführen. Wenn Sie es tatsächlich lernen und auf Ihre Anwendung anwenden, können Sie es mit Ihrem Nicht-TDD-Prozess vergleichen. Es kann sein, dass TDD tatsächlich Vorteile hat und Sie sich dafür entscheiden, es beizubehalten. Oder es kann sich herausstellen, dass TDD nichts Neues bringt und Sie nur verlangsamt. In diesem Fall können Sie auf Ihren vorherigen Prozess zurückgreifen.
quelle
Der Hauptzweck von (Einheits-) Tests besteht darin, den Code zu schützen und sicherzustellen, dass er nicht durch spätere Änderungen unbemerkt bleibt. Wenn der Code zum ersten Mal geschrieben wird, wird er viel Aufmerksamkeit erhalten und überprüft. Und dafür haben Sie vielleicht ein überlegenes System.
Sechs Monate später, wenn jemand anderes an etwas arbeitet, das scheinbar nichts damit zu tun hat, kann es kaputt gehen und Ihr Super-Duper-Code-Korrektheitsprüfer wird es nicht bemerken. Ein automatischer Test wird.
quelle
Dies ist der schwierigste Weg, TDD zu lernen. Je später Sie testen, desto mehr kostet das Schreiben von Tests und desto weniger Zeit haben Sie damit, sie zu schreiben.
Ich sage nicht, dass es unmöglich ist, Tests in eine vorhandene Codebasis nachzurüsten. Ich sage, dass dies wahrscheinlich niemanden zu einem TDD-Gläubigen machen wird. Das ist harte Arbeit.
Es ist eigentlich am besten, TDD das erste Mal an etwas Neuem und zu Hause zu üben. Auf diese Weise lernen Sie den wirklichen Rhythmus. Wenn Sie dies richtig machen, werden Sie feststellen, dass es süchtig macht.
Das ist strukturelles Denken. Sie sollten nicht Dinge wie das Testen jeder Funktion, Klasse oder jedes Moduls sagen. Diese Grenzen sind für das Testen nicht wichtig und sollten sich sowieso ändern können. Bei TDD geht es darum, ein überprüfbares Verhaltensbedürfnis zu etablieren und sich nicht darum zu kümmern, wie es befriedigt wird. Wenn es nicht so wäre, könnten wir nicht umgestalten.
Es reicht aus, sie dort anzuwenden, wo Sie sie brauchen. Ich würde mit neuem Code beginnen. Wenn Sie früh testen, erhalten Sie viel mehr zurück als spät. Tun Sie dies nicht bei der Arbeit, bis Sie genug geübt haben, um es zu Hause zu meistern.
Wenn Sie gezeigt haben, dass TDD mit dem neuen Code bei der Arbeit effektiv ist und sich sicher genug fühlt, den alten Code zu übernehmen, würde ich mit dem bewährten Code beginnen. Der Grund dafür ist, dass Sie sofort sehen können, ob die Tests, die Sie schreiben, den Code in eine gute Richtung lenken.
Tests beweisen nicht nur die Richtigkeit. Sie zeigen Absicht. Sie zeigen, was gebraucht wird. Sie weisen auf einen Weg zur Veränderung hin. Ein guter Test besagt, dass es mehrere Möglichkeiten gibt, diesen Code zu schreiben und das zu bekommen, was Sie wollen. Sie helfen neuen Programmierern zu sehen, was sie tun können, ohne alles zu beschädigen.
Erst wenn Sie das erledigt haben, sollten Sie in den unbewiesenen Code eintauchen.
Eine Warnung vor Eiferern: Sie scheinen Erfolg zu haben und werden daher wahrscheinlich nicht kopfüber springen. Aber andere, die sich beweisen wollen, werden nicht so zurückhaltend sein. TDD kann übertrieben werden. Es ist erstaunlich einfach, eine Reihe von Tests zu erstellen, die das Refactoring tatsächlich beeinträchtigen, da sie trivalente und bedeutungslose Dinge blockieren. Wie kommt es dazu? Weil Leute, die Tests vorführen wollen, nur Tests schreiben und niemals umgestalten. Lösung? Lass sie umgestalten. Lassen Sie sie mit Funktionsänderungen umgehen. Je früher desto besser. Das zeigt Ihnen schnell die nutzlosen Tests. Sie beweisen Flexibilität durch Biegen.
Eine Warnung vor struktureller Kategorisierung: Einige Leute werden darauf bestehen, dass eine Klasse eine Einheit ist. Einige nennen jeden Test mit zwei Klassen einen Integrationstest. Einige werden darauf bestehen, dass Sie die Grenze x nicht überschreiten und es einen Komponententest nennen können. Anstatt sich um irgendetwas davon zu kümmern, rate ich Ihnen, sich darum zu kümmern, wie sich Ihr Test verhält. Kann es in Sekundenbruchteilen laufen? Kann es parallel zu anderen Tests durchgeführt werden (nebenwirkungsfrei)? Kann es ausgeführt werden, ohne andere Dinge zu starten oder zu bearbeiten, um Abhängigkeiten und Voraussetzungen zu erfüllen? Ich habe diese Überlegungen vorgezogen, wenn es sich um eine Datenbank, ein Dateisystem oder ein Netzwerk handelt. Warum? Weil diese letzten drei nur Probleme sind, weil sie die anderen Probleme verursachen. Gruppieren Sie Ihre Tests danach, wie Sie erwarten können, dass sie sich verhalten. Nicht die Grenzen, die sie zufällig überschreiten. Dann wissen Sie, was Sie von jeder Testsuite erwarten können.
Diese Frage hat hier bereits Antworten .
quelle
Bei der testgetriebenen Entwicklung geht es mehr um das Prototyping und das Brainstorming einer API als um das Testen. Die erstellten Tests sind oft von schlechter Qualität und müssen schließlich weggeworfen werden. Der Hauptvorteil von TDD besteht darin, vor dem Schreiben der API-Implementierung zu bestimmen, wie eine API verwendet wird. Dieser Vorteil kann auch auf andere Weise erzielt werden, beispielsweise durch Schreiben einer API-Dokumentation vor der Implementierung.
Korrektheitsnachweise sind immer wertvoller als Tests. Tests beweisen nichts. Um Korrektheitsnachweise produktiv nutzen zu können, ist es jedoch hilfreich, einen automatisierten Proofprüfer zu haben, und Sie müssen mit Verträgen arbeiten (Design by Contract oder vertragsbasiertes Design).
In der Vergangenheit habe ich bei der Arbeit an kritischen Codeabschnitten versucht, manuelle Korrektheitsnachweise zu erbringen. Selbst informelle Beweise sind wertvoller als automatisierte Tests. Sie benötigen die Tests jedoch weiterhin, es sei denn, Sie können Ihre Proofs automatisieren, da die Benutzer in Zukunft Ihren Code beschädigen werden.
Automatisierte Tests implizieren keine TDD.
quelle
String getSomeValue()
wir hier hinzu , damit wir es testen können", wenn dies für das Gesamtdesign keinen Sinn ergibt. Sicher, Sie könnten diese Funktion später entfernen, aber meiner Erfahrung nach ist das selten.A) Wenn Sie den Code lesen und sich davon überzeugen, dass er korrekt ist, ist dies nicht annähernd der Beweis, dass er korrekt ist. Warum sonst überhaupt Tests schreiben?
B) Wenn Sie den Code ändern, möchten Sie Tests ausführen lassen, die zeigen, dass der Code immer noch korrekt ist oder nicht.
quelle
Ich möchte darauf hinweisen, dass Sie im Endspiel Zeit sparen, wenn Sie erst einmal daran gewöhnt sind, TDD effektiv einzusetzen. Es erfordert Übung, um zu lernen, wie man TDD effektiv einsetzt, und es hilft nicht, wenn Sie sich in einer Zeitkrise befinden. Wenn Sie lernen, wie Sie es am besten nutzen können, empfehle ich, mit einem persönlichen Projekt zu beginnen, bei dem Sie mehr Spielraum und weniger Zeitplandruck haben.
Sie werden feststellen, dass Ihr anfänglicher Fortschritt langsamer ist, während Sie mehr experimentieren und Ihre API schreiben. Mit der Zeit werden Sie schneller Fortschritte machen, da Ihre neuen Tests ohne Änderung des Codes bestanden werden und Sie eine sehr stabile Basis haben, auf der Sie aufbauen können. Im späten Spiel müssen Sie für Code, der nicht mit TDD erstellt wurde, viel mehr Zeit im Debugger verbringen, um herauszufinden, was falsch läuft, als erforderlich sein sollte. Sie haben auch ein höheres Risiko, etwas zu beschädigen, das früher mit neuen Änderungen gearbeitet hat. Bewerten Sie die Wirksamkeit von TDD im Vergleich zur Nichtverwendung bis zur Fertigstellung.
Trotzdem ist TDD nicht das einzige Spiel in der Stadt. Sie können BDD verwenden, das eine Standardmethode zum Ausdrücken des Verhaltens einer Full-Stack-Anwendung verwendet, und von dort aus die Richtigkeit der API bewerten.
Ihr gesamtes Argument hängt vom "Nachweis der Code-Korrektheit" ab. Sie benötigen also etwas, das die Code-Korrektheit definiert. Wenn Sie kein automatisiertes Tool verwenden, um zu definieren, was "richtig" bedeutet, ist die Definition sehr subjektiv. Wenn Ihre Definition von korrekt auf dem Konsens Ihrer Kollegen basiert, kann sich dies an einem bestimmten Tag ändern. Ihre Definition von korrekt muss konkret und überprüfbar sein, was auch bedeutet, dass sie von einem Tool bewertet werden kann. Warum nicht eins benutzen?
Der größte Gewinn bei der Verwendung automatisierter Tests jeglicher Art besteht darin, dass Sie überprüfen können, ob Ihr Code auch dann korrekt bleibt , wenn Betriebssystem-Patches schnell und effizient angewendet werden. Führen Sie Ihre Suite aus, um sicherzustellen, dass alles erfolgreich ist. Wenden Sie dann den Patch an und führen Sie die Suite erneut aus. Machen Sie es noch besser zu einem Teil Ihrer automatisierten Build-Infrastruktur. Jetzt können Sie überprüfen, ob Ihr Code nach dem Zusammenführen von Code von mehreren Entwicklern korrekt bleibt.
Meine Erfahrung mit TDD hat mich zu folgenden Schlussfolgerungen geführt:
Meine Erfahrung mit BDD hat mich zu folgenden Schlussfolgerungen geführt:
Definition von Richtig: Ihr Code entspricht den Anforderungen. Dies lässt sich am besten mit BDD überprüfen, das eine Möglichkeit bietet, diese Anforderungen auf eine für Menschen lesbare Weise auszudrücken und zur Laufzeit zu überprüfen.
Ich spreche nicht von Korrektheit in Bezug auf mathematische Beweise, was nicht möglich ist. Und ich bin es leid, dieses Argument zu haben.
quelle