Im Gegensatz zu den anderen Antworten ist es wichtig zu beachten, dass einige Testmethoden zerbrechlich werden können , wenn das zu testende System (SUT) überarbeitet wird, wenn es sich bei dem Test um eine Whitebox handelt.
Wenn ich ein Mocking-Framework verwende, das die Reihenfolge der Methoden überprüft, die für die Mocks aufgerufen wurden (wenn die Reihenfolge irrelevant ist, weil die Aufrufe frei von Nebenwirkungen sind); Wenn mein Code mit diesen Methodenaufrufen in einer anderen Reihenfolge sauberer ist und ich eine Umgestaltung vornehme, bricht mein Test ab. Im Allgemeinen können Verspottungen zu fragilen Tests führen.
Wenn ich den internen Status meines SUT überprüfe, indem ich seine privaten oder geschützten Mitglieder offenlege (wir könnten "friend" in Visual Basic verwenden oder die Zugriffsebene "internal" eskalieren und "internalsvisibleto" in C #; in vielen OO-Sprachen verwenden, einschließlich c # eine " testspezifische Unterklasse " könnte verwendet werden), dann ist plötzlich der interne Status der Klasse von Bedeutung - Sie überarbeiten die Klasse möglicherweise als Black-Box, aber White-Box-Tests schlagen fehl. Angenommen, ein einzelnes Feld wird wiederverwendet, um verschiedene Bedeutungen zu haben (keine gute Praxis!), Wenn sich der Status des SUT ändert. Wenn wir es in zwei Felder aufteilen, müssen wir möglicherweise fehlerhafte Tests neu schreiben.
Testspezifische Unterklassen können auch zum Testen geschützter Methoden verwendet werden. Dies kann bedeuten, dass ein Refaktor aus Sicht des Produktionscodes eine grundlegende Änderung aus Sicht des Testcodes darstellt. Das Verschieben einiger Zeilen in eine geschützte Methode oder aus einer geschützten Methode heraus hat möglicherweise keine produktionsbedingten Nebenwirkungen, unterbricht jedoch einen Test.
Wenn ich " Test Hooks " oder einen anderen testspezifischen oder bedingten Kompilierungscode verwende, kann es schwierig sein, sicherzustellen, dass die Tests nicht aufgrund fragiler Abhängigkeiten von der internen Logik unterbrochen werden.
Um zu verhindern, dass Tests an die intimen internen Details des SUT gekoppelt werden, kann Folgendes hilfreich sein:
- Verwenden Sie nach Möglichkeit Stubs anstelle von Mocks. Weitere Informationen finden Sie in Fabio Perieras Blog über tautologische Tests und in meinem Blog über tautologische Tests .
- Wenn Sie Mocks verwenden, sollten Sie die Reihenfolge der aufgerufenen Methoden nicht überprüfen, es sei denn, dies ist wichtig.
- Vermeiden Sie es, den internen Status Ihres SUT zu überprüfen. Verwenden Sie nach Möglichkeit dessen externe API.
- Vermeiden Sie testspezifische Logik im Produktionscode
- Vermeiden Sie es, testspezifische Unterklassen zu verwenden.
Alle obigen Punkte sind Beispiele für die in Tests verwendete White-Box-Kopplung. Verwenden Sie Black-Box-Tests des SUT, um die Umgestaltung von Bruchtests vollständig zu vermeiden.
Haftungsausschluss: Um hier das Refactoring zu diskutieren, verwende ich das Wort etwas weiter, um die Änderung der internen Implementierung ohne sichtbare externe Auswirkungen einzuschließen. Einige Puristen stimmen möglicherweise nicht überein und beziehen sich ausschließlich auf das Buch Refactoring von Martin Fowler und Kent Beck - das atomare Refactoring-Operationen beschreibt.
In der Praxis tendieren wir dazu, geringfügig größere Schritte zur Aufrechterhaltung der Unterbrechungsfreiheit als die dort beschriebenen atomaren Operationen auszuführen, und insbesondere Änderungen, die dazu führen, dass sich der Produktionscode von außen identisch verhält, führen möglicherweise nicht zum Bestehen von Tests. Aber ich denke, es ist fair, "Ersatzalgorithmus für einen anderen Algorithmus mit identischem Verhalten" als Refaktor aufzunehmen, und ich denke, Fowler stimmt dem zu. Martin Fowler selbst sagt, dass Refactoring Tests brechen kann:
Wenn Sie einen Mockist-Test schreiben, testen Sie die ausgehenden Anrufe des SUT, um sicherzustellen, dass es ordnungsgemäß mit seinen Lieferanten spricht. Bei einem klassischen Test geht es nur um den Endzustand - nicht darum, wie dieser abgeleitet wurde. Mockist-Tests sind daher eher an die Implementierung einer Methode gekoppelt. Wenn Sie die Art der Anrufe an Mitarbeiter ändern, wird in der Regel ein Spottest abgebrochen.
[...]
Die Kopplung an die Implementierung wirkt sich auch störend auf das Refactoring aus, da bei Änderungen an der Implementierung die Wahrscheinlichkeit größer ist, dass Tests abgebrochen werden als bei klassischen Tests.
Fowler - Mocks sind keine Stubs