Ich denke nachdrücklich darüber nach, einem bestehenden Projekt, das sich in der Produktion befindet, Unit-Tests hinzuzufügen. Es wurde vor 18 Monaten gestartet, bevor ich wirklich einen Nutzen von TDD (Gesichtspalme) erkennen konnte. Jetzt ist es eine ziemlich große Lösung mit einer Reihe von Projekten, und ich habe nicht die geringste Ahnung, wo ich anfangen soll, Unit-Tests hinzuzufügen. Was mich dazu bringt, dies in Betracht zu ziehen, ist, dass gelegentlich ein alter Fehler wieder auftaucht oder ein Fehler als behoben eingecheckt wird, ohne wirklich behoben zu werden. Unit-Tests würden diese Probleme reduzieren oder verhindern.
Durch Lesen ähnlich Fragen zu SO habe ich Empfehlungen wie das Starten am Bug-Tracker und das Schreiben eines Testfalls für jeden Bug gesehen, um eine Regression zu verhindern. Ich mache mir jedoch Sorgen, dass mir am Ende das Gesamtbild und grundlegende Tests fehlen, die enthalten wären, wenn ich TDD von Anfang an verwendet hätte.
Gibt es Prozesse / Schritte, die eingehalten werden sollten, um sicherzustellen, dass vorhandene Lösungen ordnungsgemäß getestet und nicht nur eingebunden werden? Wie kann ich sicherstellen , dass die Tests von guter Qualität sind und nicht nur ein Fall von jedem Test ist besser als gar keine Tests .
Also denke ich, was ich auch frage, ist;
- Lohnt sich der Aufwand für eine bestehende Lösung, die in Produktion ist?
- Wäre es besser, die Tests für dieses Projekt zu ignorieren und sie in einem möglichen zukünftigen Umschreiben hinzuzufügen?
- Was wird vorteilhafter sein; ein paar Wochen damit verbringen, Tests hinzuzufügen oder ein paar Wochen damit, Funktionen hinzuzufügen?
(Offensichtlich hängt die Antwort auf den dritten Punkt ganz davon ab, ob Sie mit dem Management oder einem Entwickler sprechen.)
Grund für Kopfgeld
Hinzufügen eines Kopfgeldes, um eine breitere Palette von Antworten zu finden, die nicht nur meinen bestehenden Verdacht bestätigen, dass dies eine gute Sache ist, sondern auch einige gute Gründe dagegen.
Ich möchte diese Frage später mit Vor- und Nachteilen aufschreiben, um dem Management zu zeigen, dass es sich lohnt, die Arbeitsstunden damit zu verbringen, die zukünftige Entwicklung des Produkts auf TDD umzustellen. Ich möchte mich dieser Herausforderung stellen und meine Argumentation ohne meinen eigenen voreingenommenen Standpunkt entwickeln.
quelle
Antworten:
Ich habe Unit-Tests für Codebasen eingeführt, die es vorher nicht hatten. Bei dem letzten großen Projekt, an dem ich beteiligt war, war das Produkt bereits mit Null-Unit-Tests in Produktion, als ich im Team ankam. Als ich - 2 Jahre später - ging, hatten wir mehr als 4500 Tests, die eine Codeabdeckung von etwa 33% in einer Codebasis mit mehr als 230.000 Produktions-LOC (finanzielle Win-Forms-Echtzeitanwendung) ergaben. Das mag leise klingen, aber das Ergebnis war eine signifikante Verbesserung der Codequalität und der Fehlerrate - plus eine verbesserte Moral und Rentabilität.
Dies ist möglich, wenn Sie sowohl ein genaues Verständnis als auch ein Engagement der beteiligten Parteien haben.
Zuallererst ist es wichtig zu verstehen, dass Unit-Tests eine Fähigkeit für sich sind. Sie können nach "konventionellen" Maßstäben ein sehr produktiver Programmierer sein und dennoch Schwierigkeiten haben, Komponententests so zu schreiben, dass sie in einem größeren Projekt skaliert werden können.
Und speziell für Ihre Situation ist das Hinzufügen von Komponententests zu einer vorhandenen Codebasis ohne Tests ebenfalls eine spezielle Fähigkeit für sich. Sofern Sie oder jemand in Ihrem Team keine erfolgreichen Erfahrungen mit der Einführung von Komponententests in eine vorhandene Codebasis haben, würde ich sagen, dass das Lesen von Feathers Buch eine Voraussetzung ist (nicht optional oder dringend empfohlen).
Der Übergang zum Unit-Test Ihres Codes ist eine Investition in Mitarbeiter und Fähigkeiten ebenso wie in die Qualität der Codebasis. Dies zu verstehen ist sehr wichtig für die Denkweise und das Management der Erwartungen.
Nun zu Ihren Kommentaren und Fragen:
Kurze Antwort: Ja, Sie werden Tests verpassen und ja, sie sehen anfangs möglicherweise nicht so aus, wie sie es auf einer grünen Wiese hätten.
Eine tiefere Antwort lautet: Es spielt keine Rolle. Sie beginnen ohne Tests. Fügen Sie Tests hinzu und überarbeiten Sie sie, während Sie fortfahren. Wenn die Fähigkeiten besser werden, legen Sie die Messlatte für den gesamten neu geschriebenen Code, der Ihrem Projekt hinzugefügt wurde, höher. Verbessere dich weiter etc ...
Wenn ich jetzt zwischen den Zeilen hier lese, habe ich den Eindruck, dass dies aus der Denkweise von "Perfektion als Entschuldigung dafür, nicht gehandelt zu haben" stammt. Eine bessere Einstellung ist es, sich auf das Selbstvertrauen zu konzentrieren. Da Sie möglicherweise noch nicht wissen, wie es geht, werden Sie herausfinden, wie Sie die Lücken ausfüllen müssen. Daher gibt es keinen Grund zur Sorge.
Wieder ist es eine Fähigkeit. Sie können nicht in einem "Prozess" oder "Schritt für Schritt" Kochbuchansatz linear von Null-Tests zu TDD-Perfektion übergehen. Es wird ein Prozess sein. Ihre Erwartungen müssen darin bestehen, schrittweise und schrittweise Fortschritte und Verbesserungen zu erzielen. Es gibt keine magische Pille.
Die gute Nachricht ist, dass Ihr Code im Laufe der Monate (und sogar Jahre) allmählich zu "richtigem", gut faktorisiertem und gut getestetem Code wird.
Als Anmerkung. Sie werden feststellen, dass das Haupthindernis für die Einführung von Komponententests in einer alten Codebasis mangelnde Kohäsion und übermäßige Abhängigkeiten sind. Sie werden daher wahrscheinlich feststellen, dass die wichtigste Fähigkeit darin besteht, vorhandene Abhängigkeiten zu lösen und Code zu entkoppeln, anstatt die eigentlichen Komponententests selbst zu schreiben.
Richten Sie einen Build-Server und einen Build für die kontinuierliche Integration ein, der bei jedem Einchecken ausgeführt wird, einschließlich aller Komponententests mit Codeabdeckung.
Trainiere deine Leute.
Beginnen Sie irgendwo und fügen Sie Tests hinzu, während Sie aus Kundensicht Fortschritte machen (siehe unten).
Verwenden Sie die Codeabdeckung als Richtschnur dafür, wie viel von Ihrer Produktionscodebasis getestet wird.
Die Erstellungszeit sollte immer SCHNELL sein. Wenn Ihre Bauzeit langsam ist, bleiben Ihre Fähigkeiten beim Testen von Einheiten zurück. Finden Sie die langsamen Tests und verbessern Sie sie (entkoppeln Sie den Produktionscode und testen Sie isoliert). Gut geschrieben, sollten Sie problemlos in der Lage sein, mehrere Tausend Unit-Tests durchzuführen und dennoch einen Build in weniger als 10 Minuten abzuschließen (~ 1-ms / Test ist eine gute, aber sehr grobe Richtlinie, einige wenige Ausnahmen können wie Code mit Reflektion usw. zutreffen ).
Inspizieren und anpassen.
Ihr eigenes Urteilsvermögen muss Ihre Hauptquelle der Realität sein. Es gibt keine Metrik, die Fähigkeiten ersetzen kann.
Wenn Sie diese Erfahrung oder dieses Urteilsvermögen nicht haben, sollten Sie jemanden beauftragen, der dies tut.
Zwei grobe sekundäre Indikatoren sind die vollständige Codeabdeckung und die Erstellungsgeschwindigkeit.
Ja. Die überwiegende Mehrheit des Geldes, das für ein kundenspezifisches System oder eine kundenspezifische Lösung ausgegeben wird, wird ausgegeben, nachdem es in Produktion gegangen ist. Und Investitionen in Qualität, Menschen und Fähigkeiten sollten niemals aus der Mode kommen.
Sie müssten nicht nur die Investition in Mitarbeiter und Fähigkeiten berücksichtigen, sondern vor allem die Gesamtbetriebskosten und die erwartete Lebensdauer des Systems.
Meine persönliche Antwort wäre in den meisten Fällen "Ja natürlich", weil ich weiß, dass es so viel besser ist, aber ich erkenne, dass es Ausnahmen geben könnte.
Weder. Ihr Ansatz sollte darin bestehen, Ihrer Codebasis Tests hinzuzufügen, während Sie Fortschritte in Bezug auf die Funktionalität erzielen.
Auch hier handelt es sich um eine Investition in Mitarbeiter, Fähigkeiten UND die Qualität der Codebasis, die Zeit benötigt. Teammitglieder müssen lernen, wie man Abhängigkeiten aufhebt, Komponententests schreibt, neue Gewohnheiten lernt, Disziplin und Qualitätsbewusstsein verbessert, Software besser entwirft usw. Es ist wichtig zu verstehen, dass Ihre Teammitglieder dies wahrscheinlich nicht tun, wenn Sie mit dem Hinzufügen von Tests beginnen Haben Sie diese Fähigkeiten noch auf dem Niveau, das sie benötigen, um erfolgreich zu sein, sodass es einfach nicht funktioniert, den Fortschritt zu stoppen, um die ganze Zeit damit zu verbringen, viele Tests hinzuzufügen.
Das Hinzufügen von Komponententests zu einer vorhandenen Codebasis mit einer beträchtlichen Projektgröße ist ein GROSSES Unterfangen, das Engagement und Beharrlichkeit erfordert. Sie können nichts Grundlegendes ändern, viel Lernen auf dem Weg erwarten und Ihren Sponsor bitten, keinen ROI zu erwarten, indem Sie den Fluss des Geschäftswerts stoppen. Das wird nicht fliegen, und ehrlich gesagt sollte es nicht.
Drittens möchten Sie Ihrem Team solide Geschäftsfokuswerte vermitteln. Qualität geht nie zu Lasten des Kunden und ohne Qualität kann man nicht schnell gehen. Außerdem lebt der Kunde in einer sich verändernden Welt, und Ihre Aufgabe ist es, ihm die Anpassung zu erleichtern. Kundenausrichtung erfordert sowohl Qualität als auch den Fluss des Geschäftswerts.
Was Sie tun, ist die Rückzahlung technischer Schulden. Und Sie tun dies, während Sie Ihren Kunden immer wieder wechselnde Bedürfnisse bedienen. Allmählich, wenn die Schulden getilgt werden, verbessert sich die Situation und es ist einfacher, den Kunden besser zu bedienen und mehr Wert zu liefern. Usw. Diese positive Dynamik sollten Sie anstreben, da sie die Grundsätze eines nachhaltigen Tempos unterstreicht und die Moral aufrechterhält und verbessert - sowohl für Ihr Entwicklungsteam, Ihren Kunden als auch für Ihre Stakeholder.
hoffentlich hilft das
quelle
Ja!
Nein!
Durch das Hinzufügen von Tests (insbesondere automatisierten Tests) wird es viel einfacher, das Projekt in Zukunft am Laufen zu halten, und es ist erheblich weniger wahrscheinlich, dass Sie dumme Probleme an den Benutzer senden.
Tests, die a priori durchgeführt werden müssen, prüfen, ob Ihrer Meinung nach die öffentliche Schnittstelle zu Ihrem Code (und zu jedem darin enthaltenen Modul) so funktioniert, wie Sie denken. Wenn Sie können, versuchen Sie auch, jeden isolierten Fehlermodus zu induzieren, den Ihre Codemodule haben sollten (beachten Sie, dass dies nicht trivial sein kann, und Sie sollten darauf achten, nicht zu sorgfältig zu überprüfen, wie Dinge fehlschlagen, z. B. wenn Sie nicht wirklich wollen Sie können beispielsweise die Anzahl der bei einem Fehler erzeugten Protokollnachrichten zählen, da die Überprüfung der Protokollierung ausreicht.
Führen Sie dann einen Test für jeden aktuellen Fehler in Ihrer Fehlerdatenbank durch, der genau den Fehler auslöst und der behoben wird, wenn der Fehler behoben ist. Dann behebe diese Fehler! :-)
Das Hinzufügen von Tests kostet im Voraus Zeit, aber Sie werden im Back-End um ein Vielfaches zurückgezahlt, da Ihr Code von viel höherer Qualität ist. Das ist enorm wichtig, wenn Sie versuchen, eine neue Version zu versenden oder Wartungsarbeiten durchzuführen.
quelle
Das Problem bei der Nachrüstung von Komponententests besteht darin, dass Sie nicht daran gedacht haben, hier eine Abhängigkeit einzufügen oder dort eine Schnittstelle zu verwenden, und dass Sie in Kürze die gesamte Komponente neu schreiben werden. Wenn Sie die Zeit dazu haben, bauen Sie sich ein schönes Sicherheitsnetz, aber Sie könnten auf dem Weg subtile Fehler eingeführt haben.
Ich war an vielen Projekten beteiligt, die vom ersten Tag an wirklich Unit-Tests benötigten, und es gibt keine einfache Möglichkeit, sie dort hinein zu bringen, abgesehen von einer vollständigen Neufassung, die normalerweise nicht gerechtfertigt werden kann, wenn der Code funktioniert und bereits Geld verdient. Vor kurzem habe ich darauf zurückgegriffen, Powershell-Skripte zu schreiben, die den Code so ausführen, dass ein Fehler reproduziert wird, sobald er ausgelöst wird, und diese Skripte dann als eine Reihe von Regressionstests für weitere Änderungen auf der ganzen Linie beizubehalten. Auf diese Weise können Sie zumindest einige Tests für die Anwendung erstellen, ohne sie zu stark zu ändern. Dies sind jedoch eher End-to-End-Regressionstests als ordnungsgemäße Komponententests.
quelle
Ich stimme dem zu, was die meisten anderen gesagt haben. Das Hinzufügen von Tests zu vorhandenem Code ist hilfreich. Ich werde diesem Punkt niemals widersprechen, aber ich möchte eine Einschränkung hinzufügen.
Das Hinzufügen von Tests zu vorhandenem Code ist zwar wertvoll, jedoch mit Kosten verbunden. Es geht zu Lasten, keine neuen Funktionen zu entwickeln. Wie sich diese beiden Dinge ausgleichen, hängt ganz vom Projekt ab, und es gibt eine Reihe von Variablen.
Lassen Sie mich noch einmal betonen, dass Tests wertvoll sind und Sie daran arbeiten sollten, Ihren alten Code zu testen. Dies ist wirklich mehr eine Frage, wie Sie es angehen. Wenn Sie es sich leisten können, alles fallen zu lassen und Ihren gesamten alten Code zu testen, tun Sie es. Wenn dies nicht realistisch ist, sollten Sie zumindest Folgendes tun
Auch dies ist kein Alles-oder-Nichts-Vorschlag. Wenn Sie ein Team von beispielsweise vier Personen haben und Ihre Fristen einhalten können, indem Sie ein oder zwei Personen in den Testdienst stellen, tun Sie dies auf jeden Fall.
Bearbeiten:
Dies ist wie die Frage "Was sind die Vor- und Nachteile der Verwendung der Quellcodeverwaltung?" oder "Was sind die Vor- und Nachteile, wenn man Leute interviewt, bevor man sie anstellt?" oder "Was sind die Vor- und Nachteile des Atmens?"
Manchmal hat das Argument nur eine Seite. Sie benötigen automatisierte Tests in irgendeiner Form für jedes Projekt jeder Komplexität. Nein, Tests schreiben sich nicht selbst, und ja, es wird etwas länger dauern, bis die Dinge aus der Tür kommen. Aber auf lange Sicht wird es mehr Zeit und Geld kosten, Fehler nachträglich zu beheben, als Tests im Voraus zu schreiben. Zeitraum. Das ist alles dazu.
quelle
Als wir anfingen, Tests hinzuzufügen, handelte es sich um eine zehn Jahre alte Codebasis mit ungefähr einer Million Zeilen und viel zu viel Logik in der Benutzeroberfläche und im Berichtscode.
Eines der ersten Dinge, die wir (nach dem Einrichten eines kontinuierlichen Build-Servers) getan haben, war das Hinzufügen von Regressionstests. Dies waren End-to-End-Tests.
Der Zweck von Regressionstests besteht darin, Ihnen mitzuteilen, ob sich etwas ändert. Das bedeutet, dass sie fehlschlagen, wenn Sie etwas kaputt gemacht haben, aber auch, wenn Sie absichtlich etwas geändert haben (in diesem Fall besteht die Lösung darin, die Snapshot-Datei zu aktualisieren). Sie wissen nicht, dass die Snapshot-Dateien überhaupt korrekt sind - möglicherweise sind Fehler im System vorhanden (und wenn Sie diese Fehler beheben, schlagen die Regressionstests fehl).
Trotzdem waren Regressionstests ein großer Gewinn für uns. Nahezu alles in unserem System verfügt über einen Bericht. Durch ein paar Wochen, in denen wir ein Testgeschirr für die Berichte erstellt haben, konnten wir einen großen Teil unserer Codebasis abdecken. Das Schreiben der entsprechenden Unit-Tests hätte Monate oder Jahre gedauert. (Unit-Tests hätten uns eine weitaus bessere Abdeckung gegeben und wären weitaus weniger zerbrechlich gewesen; aber ich hätte jetzt lieber etwas, anstatt Jahre auf Perfektion zu warten.)
Dann gingen wir zurück und fügten Unit-Tests hinzu, wenn wir Fehler behoben oder Verbesserungen hinzugefügt haben oder etwas Code verstehen mussten. Regressionstests machen Unit-Tests in keiner Weise überflüssig. Sie sind nur ein Sicherheitsnetz der ersten Ebene, sodass Sie schnell eine gewisse Testabdeckung erhalten. Anschließend können Sie mit dem Refactoring beginnen, um Abhängigkeiten zu lösen, sodass Sie Komponententests hinzufügen können. und die Regressionstests geben Ihnen ein gewisses Maß an Sicherheit, dass Ihr Refactoring nichts kaputt macht.
Regressionstests haben Probleme: Sie sind langsam und es gibt zu viele Gründe, warum sie brechen können. Aber zumindest für uns waren sie es so wert. Sie haben in den letzten fünf Jahren unzählige Fehler entdeckt und sie fangen sie innerhalb weniger Stunden, anstatt auf einen QS-Zyklus zu warten. Wir haben immer noch diese ursprünglichen Regressionstests, verteilt auf sieben verschiedene Maschinen mit kontinuierlichem Aufbau (getrennt von der Maschine, auf der die schnellen Komponententests ausgeführt werden), und wir ergänzen sie sogar von Zeit zu Zeit, weil wir immer noch so viel Code haben, dass unsere 6.000 + Unit-Tests decken nicht ab.
quelle
Es ist es absolut wert. Unsere App verfügt über komplexe Regeln für die gegenseitige Validierung, und wir mussten kürzlich wesentliche Änderungen an den Geschäftsregeln vornehmen. Es kam zu Konflikten, die den Benutzer am Speichern hinderten. Mir wurde klar, dass es ewig dauern würde, es in der Anwendung zu klären (es dauert einige Minuten, bis der Punkt erreicht ist, an dem die Probleme aufgetreten sind). Ich wollte automatisierte Komponententests einführen und hatte das Framework installiert, aber ich hatte nichts weiter getan als ein paar Dummy-Tests, um sicherzustellen, dass die Dinge funktionierten. Mit den neuen Geschäftsregeln begann ich, Tests zu schreiben. Die Tests identifizierten schnell die Bedingungen, die die Konflikte verursachten, und wir konnten die Regeln klären.
Wenn Sie Tests schreiben, die die Funktionen abdecken, die Sie hinzufügen oder ändern, erhalten Sie sofort einen Vorteil. Wenn Sie auf ein erneutes Schreiben warten, werden möglicherweise nie automatisierte Tests durchgeführt.
Sie sollten nicht viel Zeit damit verbringen, Tests für vorhandene Dinge zu schreiben, die bereits funktionieren. In den meisten Fällen haben Sie keine Spezifikation für den vorhandenen Code. Die Hauptsache, die Sie testen, ist Ihre Fähigkeit zum Reverse Engineering. Wenn Sie jedoch etwas ändern möchten, müssen Sie diese Funktionalität mit Tests abdecken, damit Sie wissen, dass Sie die Änderungen korrekt vorgenommen haben. Und natürlich schreiben Sie für neue Funktionen fehlgeschlagene Tests und implementieren Sie dann die fehlende Funktionalität.
quelle
Ich werde meine Stimme hinzufügen und ja sagen, es ist immer nützlich!
Es gibt jedoch einige Unterschiede, die Sie beachten sollten: Black-Box gegen White-Box und Einheit gegen Funktion. Da die Definitionen variieren, meine ich Folgendes:
Als ich spät im Spiel einem Versandprodukt Tests hinzufügte, stellte ich fest, dass ich durch White-Box- und Funktionstests das Beste für das Geld bekam . Wenn ein Teil des Codes, von dem Sie wissen, dass er besonders zerbrechlich ist, White-Box-Tests schreibt, um die Problemfälle abzudecken und sicherzustellen, dass er nicht zweimal auf dieselbe Weise beschädigt wird. In ähnlicher Weise sind Funktionstests des gesamten Systems eine nützliche Überprüfung der Integrität, mit der Sie sicherstellen können, dass Sie niemals die 10 häufigsten Anwendungsfälle brechen.
Black-Box- und Unit-Tests kleiner Einheiten sind ebenfalls nützlich. Wenn Ihre Zeit jedoch begrenzt ist, sollten Sie sie frühzeitig hinzufügen. Zum Zeitpunkt des Versands haben Sie im Allgemeinen (auf die harte Tour) die meisten Randfälle und Probleme gefunden, die diese Tests festgestellt hätten.
Wie die anderen werde ich Sie auch an die beiden wichtigsten Dinge bei TDD erinnern:
quelle
Ob es sich lohnt, einer in Produktion befindlichen App Komponententests hinzuzufügen, hängt von den Kosten für die Wartung der App ab. Wenn die App nur wenige Fehler und Verbesserungswünsche aufweist, lohnt sich die Mühe möglicherweise nicht. OTOH, wenn die App fehlerhaft ist oder häufig geändert wird, sind Unit-Tests von großem Vorteil.
Denken Sie an dieser Stelle daran, dass ich über das selektive Hinzufügen von Komponententests spreche und nicht versuche, eine Reihe von Tests zu generieren, die denen ähneln, die existieren würden, wenn Sie TDD von Anfang an geübt hätten. Als Antwort auf die zweite Hälfte Ihrer zweiten Frage: Verwenden Sie TDD bei Ihrem nächsten Projekt, sei es ein neues Projekt oder ein Umschreiben (Entschuldigung, aber hier ist ein Link zu einem anderen Buch, das Sie wirklich lesen sollten : Wachsende objektorientierte Software, die von Tests geleitet wird )
Meine Antwort auf Ihre dritte Frage ist dieselbe wie die erste: Sie hängt vom Kontext Ihres Projekts ab.
In Ihren Beitrag ist eine weitere Frage eingebettet, wie Sie sicherstellen können, dass alle nachgerüsteten Tests ordnungsgemäß durchgeführt werden . Es ist wichtig sicherzustellen, dass Unit-Tests tatsächlich Unit- Tests sind, und dies bedeutet (meistens), dass für Nachrüsttests der vorhandene Code überarbeitet werden muss, um die Entkopplung Ihrer Schichten / Komponenten zu ermöglichen (vgl. Abhängigkeitsinjektion; Umkehrung der Kontrolle; Stubbing; Verspottung). Wenn Sie dies nicht erzwingen, werden Ihre Tests zu Integrationstests, die nützlich, aber weniger zielgerichtet und spröder als echte Komponententests sind.
quelle
Sie erwähnen die Implementierungssprache nicht, aber wenn Sie in Java sind, können Sie diesen Ansatz ausprobieren:
Erstellen Sie in einem separaten Quellbaum Regressionstests oder Rauchtests, indem Sie sie mithilfe eines Tools generieren, um eine Abdeckung von nahezu 80% zu erzielen. Diese Tests führen alle Codelogikpfade aus und stellen ab diesem Zeitpunkt sicher, dass der Code immer noch genau das tut, was er derzeit tut (auch wenn ein Fehler vorliegt). Auf diese Weise erhalten Sie ein Sicherheitsnetz gegen unbeabsichtigtes Verhaltensänderungen, wenn Sie das erforderliche Refactoring durchführen, um den Code einfach von Hand testbar zu machen.
Verwenden Sie für jeden Fehler oder jede Funktion, die Sie von nun an hinzufügen, einen TDD-Ansatz, um sicherzustellen, dass neuer Code testbar ist, und platzieren Sie diese Tests in einem normalen Testquellbaum.
Bestehender Code muss wahrscheinlich auch geändert oder überarbeitet werden, damit er im Rahmen des Hinzufügens neuer Funktionen getestet werden kann. Ihre Rauchtests geben Ihnen ein Sicherheitsnetz gegen Regressionen oder unbeabsichtigte subtile Verhaltensänderungen.
Wenn Sie Änderungen (Fehlerbehebungen oder Funktionen) über TDD vornehmen, schlägt der begleitende Rauchtest wahrscheinlich fehl, wenn er abgeschlossen ist. Stellen Sie sicher, dass die Fehler aufgrund der vorgenommenen Änderungen wie erwartet sind, und entfernen Sie den weniger lesbaren Rauchtest, da Ihr handgeschriebener Komponententest diese verbesserte Komponente vollständig abdeckt. Stellen Sie sicher, dass Ihre Testabdeckung nicht abnimmt, sondern nur gleich bleibt oder zunimmt.
Wenn Sie Fehler beheben, schreiben Sie einen fehlgeschlagenen Komponententest, der den Fehler zuerst aufdeckt.
quelle
Ich möchte diese Antwort damit beginnen, dass Unit-Tests wirklich wichtig sind, da sie Ihnen helfen, Fehler zu beseitigen, bevor sie sich in die Produktion einschleichen.
Identifizieren Sie die Bereiche Projekte / Module, in denen Fehler erneut eingeführt wurden. Beginnen Sie mit diesen Projekten, um Tests zu schreiben. Es ist durchaus sinnvoll, Tests für neue Funktionen und zur Fehlerbehebung zu schreiben.
Ja. Sie werden feststellen, dass Fehler auftreten und die Wartung einfacher wird
Ich würde empfehlen, ab sofort zu beginnen.
Sie stellen die falsche Frage. Funktionalität ist auf jeden Fall wichtiger als alles andere. Sie sollten sich jedoch fragen, ob ein paar Wochen Test hinzufügen mein System stabiler machen. Hilft dies meinem Endbenutzer? Wird es einem neuen Entwickler im Team helfen, das Projekt zu verstehen und sicherzustellen, dass er / sie keinen Fehler einführt, weil er die Gesamtauswirkungen einer Änderung nicht versteht?
quelle
Ich mag Refactor, die niedrig hängende Frucht, als Antwort auf die Frage, wo ich mit dem Refactoring beginnen soll, sehr. Dies ist eine Möglichkeit, sich in ein besseres Design zu verwandeln, ohne mehr abzubeißen, als Sie kauen können.
Ich denke, die gleiche Logik gilt für TDD - oder nur für Unit-Tests: Schreiben Sie die Tests, die Sie benötigen, so, wie Sie sie benötigen. Tests für neuen Code schreiben; Schreiben Sie Tests auf auftretende Fehler. Sie haben Angst, schwer zugängliche Bereiche der Codebasis zu vernachlässigen, und dies ist sicherlich ein Risiko, aber als Einstieg: Starten Sie! Sie können das Risiko später mit Tools zur Codeabdeckung verringern, und das Risiko ist (meiner Meinung nach) sowieso nicht so groß: Wenn Sie die Fehler abdecken, den neuen Code abdecken, den Code abdecken, den Sie sich ansehen Dann decken Sie den Code ab, der den größten Testbedarf hat.
quelle
quelle
Ja, das kann es: Versuchen Sie einfach sicherzustellen, dass für den gesamten Code, den Sie jetzt schreiben, ein Test vorhanden ist.
Wenn der bereits vorhandene Code geändert werden muss und getestet werden kann, tun Sie dies. Es ist jedoch besser, nicht zu energisch zu versuchen, Tests für stabilen Code durchzuführen. Solche Dinge haben tendenziell einen Anstoßeffekt und können außer Kontrolle geraten.
quelle
quelle
Aktualisieren
6 Jahre nach der ursprünglichen Antwort habe ich eine etwas andere Einstellung.
Ich denke, es ist sinnvoll, jedem neuen Code, den Sie schreiben, Komponententests hinzuzufügen - und dann Stellen umzugestalten, an denen Sie Änderungen vornehmen, um sie testbar zu machen.
Das gleichzeitige Schreiben von Tests für Ihren gesamten vorhandenen Code hilft nicht - aber auch das Schreiben von Tests für neuen Code, den Sie schreiben (oder Bereiche, die Sie ändern), ist nicht sinnvoll. Das Hinzufügen von Tests beim Refactor / Hinzufügen von Dingen ist wahrscheinlich der beste Weg, um Tests hinzuzufügen und den Code in einem vorhandenen Projekt ohne Tests wartbarer zu machen.
Frühere Antwort
Ich werde hier ein paar Augenbrauen hochziehen :)
Was ist Ihr Projekt? Wenn es sich um einen Compiler, eine Sprache, ein Framework oder etwas anderes handelt, das sich lange Zeit nicht funktional ändern wird, finde ich es absolut fantastisch, Unit-Tests hinzuzufügen.
Wenn Sie jedoch an einer Anwendung arbeiten, für die wahrscheinlich Änderungen in der Funktionalität erforderlich sind (aufgrund sich ändernder Anforderungen), ist es sinnlos, diesen zusätzlichen Aufwand zu betreiben.
Warum?
Unit-Tests decken nur Codetests ab - unabhängig davon, ob der Code das tut, wofür er entwickelt wurde - er ist kein Ersatz für manuelle Tests, die sowieso durchgeführt werden müssen (um Funktionsfehler, Usability-Probleme und alle anderen Arten von Problemen aufzudecken).
Unit-Tests kosten Zeit! Woher ich komme, ist das ein kostbares Gut - und das Geschäft wählt im Allgemeinen eine bessere Funktionalität als eine komplette Testsuite.
Wenn Ihre Anwendung für Benutzer auch nur aus der Ferne nützlich ist, werden sie Änderungen anfordern. Sie werden also Versionen haben, die die Dinge besser, schneller und wahrscheinlich neu machen. Wenn Ihr Code wächst, wird möglicherweise auch viel umgestaltet. Die Wartung einer ausgewachsenen Unit-Test-Suite in einer dynamischen Umgebung bereitet Kopfschmerzen.
Unit-Tests haben keinen Einfluss auf die wahrgenommene Qualität Ihres Produkts - die Qualität, die der Benutzer sieht. Sicher, Ihre Methoden funktionieren möglicherweise genauso wie am ersten Tag. Die Schnittstelle zwischen Präsentations- und Geschäftsschicht ist möglicherweise makellos - aber wissen Sie was? Dem Benutzer ist das egal! Lassen Sie einige echte Tester Ihre Anwendung testen. Und meistens müssen sich diese Methoden und Schnittstellen früher oder später sowieso ändern.
Was wird vorteilhafter sein; ein paar Wochen damit verbringen, Tests hinzuzufügen oder ein paar Wochen damit, Funktionen hinzuzufügen? - Es gibt verdammt viele Dinge, die Sie besser machen können als Tests zu schreiben. - Schreiben Sie neue Funktionen, verbessern Sie die Leistung, verbessern Sie die Benutzerfreundlichkeit, schreiben Sie bessere Hilfehandbücher, beheben Sie ausstehende Fehler usw. usw.
Versteh mich jetzt nicht falsch - Wenn Sie absolut sicher sind, dass sich die Dinge in den nächsten 100 Jahren nicht ändern werden, machen Sie weiter, schlagen Sie sich aus und schreiben Sie diese Tests. Automatisierte Tests sind auch eine großartige Idee für APIs, bei denen Sie den Code von Drittanbietern absolut nicht beschädigen möchten. Überall sonst ist es nur etwas, das mich später versenden lässt!
quelle
Es ist unwahrscheinlich, dass Sie jemals eine signifikante Testabdeckung haben werden. Sie müssen also taktisch sein, wo Sie Tests hinzufügen:
OTOH, es lohnt sich nicht, nur herumzusitzen und Tests über Code zu schreiben, mit dem die Leute zufrieden sind - besonders wenn niemand ihn ändern wird. Es bringt einfach keinen Mehrwert (außer vielleicht das Verhalten des Systems zu verstehen).
Viel Glück!
quelle
Sie sagen, Sie möchten kein weiteres Buch kaufen. Lesen Sie einfach den Artikel von Michael Feather über die effektive Arbeit mit Legacy-Code . Dann kauf das Buch :)
quelle
Wenn ich an Ihrer Stelle wäre, würde ich wahrscheinlich von außen nach innen vorgehen und mit Funktionstests beginnen, die das gesamte System trainieren. Ich würde versuchen, die Systemanforderungen mithilfe einer BDD-Spezifikationssprache wie RSpec neu zu dokumentieren und dann Tests zu schreiben, um diese Anforderungen durch Automatisierung der Benutzeroberfläche zu überprüfen.
Dann würde ich eine fehlergesteuerte Entwicklung für neu entdeckte Fehler durchführen, Komponententests schreiben, um die Probleme zu reproduzieren, und an den Fehlern arbeiten, bis die Tests bestanden sind.
Bei neuen Funktionen würde ich mich an den Outside-In-Ansatz halten: Beginnen Sie mit Funktionen, die in RSpec dokumentiert und durch Automatisierung der Benutzeroberfläche überprüft werden (was natürlich zunächst fehlschlägt), und fügen Sie dann im Verlauf der Implementierung feinkörnigere Komponententests hinzu.
Ich bin kein Experte für diesen Prozess, aber aus meiner geringen Erfahrung kann ich Ihnen sagen, dass BDD über automatisierte UI-Tests nicht einfach ist, aber ich denke, es ist die Mühe wert und würde in Ihrem Fall wahrscheinlich den größten Nutzen bringen.
quelle
Ich bin keineswegs ein erfahrener TDD-Experte, aber natürlich würde ich sagen, dass es unglaublich wichtig ist, so viele Tests wie möglich durchzuführen. Da der Code bereits vorhanden ist, würde ich zunächst eine Art Unit-Test-Automatisierung einrichten. Ich verwende TeamCity, um alle Tests in meinen Projekten durchzuführen, und es gibt Ihnen eine schöne Zusammenfassung der Funktionsweise der Komponenten.
Wenn das so ist, würde ich zu den wirklich kritischen Komponenten der Geschäftslogik übergehen, die nicht scheitern können. In meinem Fall gibt es einige grundlegende Trigometrieprobleme, die für verschiedene Eingaben gelöst werden müssen, also teste ich diese zum Teufel. Der Grund, warum ich das tue, ist, dass es beim Verbrennen des Mitternachtsöls sehr einfach ist, Zeit damit zu verschwenden, in Codetiefen zu graben, die wirklich nicht berührt werden müssen, weil Sie wissen, dass sie getestet wurden alle möglichen Eingaben werden (In meinem Fall gibt es eine begrenzte Anzahl von Eingaben).
Ok, jetzt fühlen Sie sich hoffentlich besser bei diesen kritischen Stücken. Anstatt mich hinzusetzen und alle Tests zu knallen, würde ich sie angreifen, wenn sie auftauchen. Wenn Sie auf einen Fehler stoßen, der durch eine echte PITA behoben werden muss, schreiben Sie die Komponententests dafür und stellen Sie sie aus dem Weg.
Es gibt Fälle, in denen Sie feststellen, dass das Testen schwierig ist, weil Sie eine bestimmte Klasse aus dem Test nicht instanziieren können, also müssen Sie sie verspotten. Oh, aber vielleicht können Sie es nicht einfach verspotten, weil Sie nicht auf eine Schnittstelle geschrieben haben. Ich nehme diese "Whoops" -Szenarien als Gelegenheit, diese Schnittstelle zu implementieren, denn es ist eine gute Sache.
Von dort aus würde ich Ihren Build-Server oder die von Ihnen installierte Automatisierung mit einem Tool zur Codeabdeckung konfigurieren lassen. Sie erstellen böse Balkendiagramme mit großen roten Zonen, in denen Sie eine schlechte Abdeckung haben. Jetzt ist 100% Deckung nicht Ihr Ziel, und 100% Deckung würde nicht unbedingt bedeuten, dass Ihr Code kugelsicher ist, aber der rote Balken motiviert mich definitiv, wenn ich Freizeit habe. :) :)
quelle
Es gibt so viele gute Antworten, dass ich ihren Inhalt nicht wiederholen werde. Ich habe Ihr Profil überprüft und anscheinend sind Sie C # .NET-Entwickler. Aus diesem Grund füge ich einen Verweis auf das Microsoft PEX- und Moles- Projekt hinzu, das Ihnen bei der automatischen Generierung von Komponententests für Legacy-Code helfen kann. Ich weiß, dass die automatische Generierung nicht der beste Weg ist, aber zumindest der Anfang. Lesen Sie diesen sehr interessanten Artikel aus dem MSDN-Magazin über die Verwendung von PEX für Legacy-Code .
quelle
Ich schlage vor, einen brillanten Artikel eines TopTal-Ingenieurs zu lesen, in dem erklärt wird, wo mit dem Hinzufügen von Tests begonnen werden soll: Er enthält viel Mathematik, aber die Grundidee lautet:
1) Messen Sie die afferente Kopplung (CA) Ihres Codes (wie oft eine Klasse von anderen Klassen verwendet wird, was bedeutet, dass das Brechen der Klasse weit verbreiteten Schaden verursachen würde).
2) Messen Sie die zyklomatische Komplexität (CC) Ihres Codes (höhere Komplexität = höhere Änderung der Unterbrechung)
Warum? Weil eine hohe CA, aber sehr niedrige CC-Klassen sehr wichtig sind, aber wahrscheinlich nicht brechen. Auf der anderen Seite brechen niedrige CA, aber hohe CC wahrscheinlich, verursachen aber weniger Schaden. Sie wollen also ausbalancieren.
quelle
Es kommt darauf an ...
Es ist großartig, Unit-Tests durchzuführen, aber Sie müssen überlegen, wer Ihre Benutzer sind und was sie zu tolerieren bereit sind, um ein fehlerfreieres Produkt zu erhalten. Wenn Sie Ihren Code, der derzeit keine Komponententests enthält, überarbeiten, werden Sie unweigerlich Fehler einführen, und vielen Benutzern fällt es schwer zu verstehen, dass Sie das Produkt vorübergehend fehlerhafter machen, um es auf lange Sicht weniger fehlerhaft zu machen. Letztendlich sind es die Benutzer, die das letzte Wort haben ...
quelle
Ja. Tests hinzufügen.
Wenn Sie sich für einen TDD-Ansatz entscheiden, können Sie Ihre Bemühungen, neue Funktionen hinzuzufügen und Regressionstests erheblich zu vereinfachen, besser informieren. Hör zu!
quelle