Refactor Unit Tests?
Wenn wir mit Legacy-Code arbeiten und Änderungen vornehmen müssen, schreiben wir zuerst Tests zum aktuellen Verhalten. Auf diese Weise können wir neue Änderungen mit Zuversicht umsetzen. Wir können den Code sogar umgestalten.
Legacy-Code ist oft schlechter Code, und nach einigen Umgestaltungen kann der Code einfacher und leichter zu testen sein. Da der Refactor durch die Tests validiert wurde, sollten wir die Tests auch refactorisieren, wenn wir sie einfacher / klarer machen oder so lassen können, wie sie geschrieben wurden?
Antworten
Automatisierte Tests sind Code, daher ist es sinnvoll, diesen Code beizubehalten, gegebenenfalls einschließlich Refactoring-Tests. Jedoch:
Produktivcode und Tests haben unterschiedliche Qualitätsanforderungen
- Investiere keine Zeit in Dinge, die keine Rolle spielen
Produktiver Code sollte eine einzige Quelle der Wahrheit haben, während Tests weitgehend in sich geschlossen sein sollten
- Vervielfältigung ist nicht unbedingt schlecht
Und wie Ewan betont, sollten Sie niemals den Code und die Tests gleichzeitig ändern. Code + Tests sind zusammen ein Selbsttestsystem. Eine Änderung in einem Teil wird überprüft, indem es zusammen mit dem anderen Teil ausgeführt wird. Wenn Sie beide gleichzeitig ändern, wird diese Sicherheit aufgegeben. Dies ist in der Praxis nicht immer möglich (z. B. beim Ändern eines Querschnittsthemas wie einer zugrunde liegenden Standardbibliothek), aber es wäre dumm, diese Sicherheit ohne großen Bedarf aufzugeben.
Häufige Gründe, warum ich Tests in keiner bestimmten Reihenfolge überarbeitet habe: Die zu testende API wurde geändert und auf einen anderen Testansatz umgestellt (z. B. szenariobasierte Tests im Vergleich zu eigenschaftsbasierten Tests, Tests auf API-Ebene im Vergleich zu Tests auf Verhaltensebene) Test-Framework (z. B. um bessere Fehlerberichte zu erhalten oder parametrisierte Tests zu verwenden), Ändern der Testorganisation (z. B. xUnit-Stil-Suites und -Fälle im Vergleich zum RSpec-Stil), Entfernen von akkumulierten Duplikaten (z. B. Extrahieren von allgemeinem Code zum Erstellen eines Fixtures) ,…
Wenn wir mit Legacy-Code arbeiten und Änderungen vornehmen müssen, schreiben wir zuerst Tests zum aktuellen Verhalten. Auf diese Weise können wir neue Änderungen mit Zuversicht umsetzen. Wir können den Code sogar umgestalten.
Das mag manchmal Ihren Arbeitsprozess widerspiegeln, aber meiner Erfahrung nach ist ein effizienterer Prozess:
Sie schreiben Tests
Sie überarbeiten, um eine Änderung zu vereinfachen
Sie implementieren die Änderung
Auf diese Weise wird deutlicher, dass Sie umgestalten, wenn es einen echten Grund für eine Änderung gibt , nicht nur, weil der Code "nicht mehr sauber ist".
Versuchen Sie nun, die gleichen Maßnahmen auf Ihre Tests anzuwenden: Sie überarbeiten Ihre Tests nicht, weil "sie nicht mehr sauber sind" . Sie überarbeiten sie, wenn sie Sie daran hindern, einfache Änderungen an Ihrem vorhandenen Code vorzunehmen.
Wenn Sie beispielsweise zehn Tests haben, die alle dieselbe öffentliche Methode einer zu testenden Klasse aufrufen, während in Ihrem Produktionscode diese öffentliche Methode nur an einer Stelle aufgerufen wird, ist dies eine Form der Codeduplizierung durch Tests, die Sie möglicherweise behindern Ändern Sie die Signatur dieser öffentlichen Methode.
Normalerweise lasse ich es so, es sei denn, Sie erhalten wirklich die Anforderung für Letzteres oder allgemeiner: Wenn Sie diese Codeduplizierung bemerken, müssen Sie an mehreren Stellen dieselbe Änderung an Ihren Tests vornehmen.
Möglicherweise möchten Sie mit der Überarbeitung der Tests beginnen.
Die Tests erfassen, was die Legacy-Anwendung tut. eine Art Dokumentation. Tests sagen Ihnen Eingabe und Ausgabe, Code sagt Ihnen Prozess. Wenn die Tests schlecht sind, können Sie den Code besser aufräumen, je nachdem, wie schlecht sie sind.
Es ist auch eine gute Möglichkeit zu beurteilen, ob die Tests einen Mehrwert bieten. Ein Legacy-System, an dem ich gearbeitet habe, hatte eine hervorragende Codeabdeckung, aber bei der Überprüfung wurden die Tests auf sinnlose Dinge bestätigt ... wie das Sicherstellen, dass Getters und Setter funktionieren (Testen des .NET-Frameworks, nicht der Anwendung).
Sobald Sie einen sauberen Test erhalten haben, haben Sie ein besseres Verständnis des Codes und können dann bessere Entscheidungen darüber treffen, wie der Code umgestaltet werden soll.