Eine Sache beim automatisierten Testen ist, dass Sie Code schreiben müssen, um testbar zu sein. Dies ist an und für sich keine schlechte Sache (in der Tat ist es gut, weil es von vielen Praktiken abhält, die in der Regel vermieden werden sollten), aber wenn Sie versuchen, Komponententests auf vorhandenen Code anzuwenden, ist dies wahrscheinlich nicht der Fall wurde auf überprüfbare Weise geschrieben.
Dinge wie Singletons, statische Methoden, Registries, Service Locators und so weiter führen zu Abhängigkeiten, die nur sehr schwer auszumachen sind. Verstöße gegen das Gesetz von Demeter bedeuten, dass zu viele Teile Ihrer Codebasis zu viel darüber wissen, wie andere Teile Ihrer Codebasis funktionieren, was zu weiteren versteckten Abhängigkeiten führt, die möglicherweise schwer zu knacken sind. All diese Dinge machen es schwierig, ein Modul vom Rest der Codebasis zu isolieren, und wenn Sie Ihre Module nicht isoliert testen können, verlieren Unit-Tests viel an Wert. Wenn ein Test fehlschlägt, liegt dies an einem Fehler im zu testenden Gerät oder an einem Fehler in einer seiner Abhängigkeiten, oder möglicherweise daran, dass die Daten, die über eine abhängige Datenquelle abgerufen werden, nicht den Erwartungen des Testschreibers entsprechen ? Falls Sie können'
Die meisten Codebasen, die ich gesehen habe und die nicht für Komponententests entwickelt wurden, sind in der Regel von Natur aus nicht testbar, da sich Codierer eher darauf konzentrieren, den Code so zu gestalten, wie sie es erwarten, als die Arbeit zu leisten, die erforderlich ist, um die Kopplung und die Abhängigkeiten explizit zu halten . Code, der unter Berücksichtigung von Komponententests geschrieben wurde, sieht normalerweise ganz anders aus.
Viele Leute gehen naiv mit Unit-Tests um, wenn sie zum ersten Mal damit beginnen. Sie denken, sie können einfach eine Menge Tests für eine vorhandene Codebasis schreiben und alles wird gut, aber es funktioniert nie so, weil die oben genannten Probleme. Sie stellen fest, dass sie in Unit-Tests übermäßig viele Setups ausführen müssen, um überhaupt ausgeführt zu werden, und die Ergebnisse sind häufig fragwürdig, da die fehlende Isolation im Code bedeutet, dass Sie nicht nachvollziehen können, was einen Testfehler verursacht hat. Sie tendieren auch dazu, zunächst zu versuchen, "clevere" Tests zu schreiben, die einen sehr abstrakten Aspekt der Funktionsweise des Systems demonstrieren. Dies kann zum Scheitern führen, da ein "cleverer" Komponententest selbst eine potenzielle Fehlerquelle darstellt. Ist der Test aufgrund eines Fehlers im getesteten Modul fehlgeschlagen? oder wegen einem fehler im test? Ein Test sollte so qualvoll einfach sein, dass es offensichtlich keine Möglichkeit gibt, dass sich ein Fehler darin versteckt. Tatsächlich sind die besten Tests selten länger als zwei Zeilen. Die erste Zeile weist das zu testende Gerät an, etwas zu tun. Die zweite Zeile gibt an, dass das, was getan wurde, das war, was erwartet wurde.
Wenn es Ihrem Team ernst ist, Unit-Tests einzuführen, ist es nicht ratsam, mit einem vorhandenen Projekt zu beginnen. Die bestehenden Projekte Ihres Teams sind ohne größere Umgestaltung wahrscheinlich nicht testbar. Sie sollten besser ein neues Projekt als Grundlage für das Erlernen von Unit-Tests verwenden, da Sie einen sauberen Plan haben, mit dem Sie arbeiten können. Sie können die neue Codebasis so entwerfen, dass die Abhängigkeitsinjektion Singletons, Registries und anderen solchen versteckten Abhängigkeiten vorgezogen wird. Sie können sie so schreiben, dass sie von Schnittstellen anstelle von Implementierungen usw. abhängt. Sie können (und sollten) die Tests auch neben den zu testenden Code schreiben, da das anschließende Schreiben der Tests zu Komponententests führt, die sicherstellen, dass das getestete Modul das tut, von dem Sie glauben, dass es dazu bestimmt ist, und nicht diejenigen, die es testen Was die Spezifikationen sagen, sollte es tun.
Sobald Sie mit Unit-Tests ein gewisses Maß an Sicherheit erlangt haben, wird Ihr Team wahrscheinlich beginnen, die Fehler im vorhandenen Code zu erkennen, die Hindernisse für Unit-Tests darstellen werden. Dies ist der Zeitpunkt, an dem Sie beginnen können, vorhandenen Code zu überarbeiten, um ihn testbarer zu machen. Seien Sie nicht ehrgeizig und versuchen Sie, dies alles auf einmal zu tun, oder versuchen Sie, ein System zu ersetzen, das mit einem völlig neuen funktioniert. Suchen Sie einfach die Teile der Codebasis, die leicht getestet werden können (diejenigen, die keine haben) Abhängigkeiten oder wo die Abhängigkeiten offensichtlich sind) und schreiben Sie Tests für diese. Ich weiß, dass ich gesagt habe, dass das Schreiben eines Tests neben Code dem Schreiben von Tests nach dem Schreiben vorzuziehen ist, aber selbst ein später geschriebener Test hat immer noch Wert als Ausgangspunkt. Schreiben Sie die Tests so, als wüssten Sie nichts anderes über die Funktionsweise der Klasse als die in den Spezifikationen angegebenen. Wenn Sie die Tests ausführen und Fehler feststellen, ist entweder die Spezifikation oder die Implementierung falsch. Überprüfen Sie beide, um festzustellen, was falsch ist, und aktualisieren Sie entweder den Test oder den Code entsprechend.
Sobald Sie die tief hängenden Früchte gepflückt haben, beginnt Ihre eigentliche Arbeit. Sie müssen nacheinander die versteckten Abhängigkeiten in Ihrer Codebasis suchen und korrigieren. Werden Sie zu diesem Zeitpunkt nicht zu ehrgeizig, bleiben Sie einfach bei einem Modul oder auch nur einem einzelnen Problem in einem Modul, bis die Hindernisse für das Testen behoben sind und Sie mit dem nächsten Schritt fortfahren können.
TL: DR: Die meisten Leute denken, dass das Testen einfach ist und dass Sie Tests einfach in vorhandenen Code nachrüsten können. Diese beiden Annahmen sind falsch. Wenn Sie sich auf ein Projekt einlassen, um Unit-Tests in Ihre Projekte zu integrieren, sind Sie mit größerer Wahrscheinlichkeit erfolgreich.