Ich bin erstaunt, dass diese Frage schon so lange gestellt wird und noch niemand eine Antwort auf der Grundlage folgender Kriterien gegeben hat Roy Osheroves "Die Kunst des Unit-Testens" .
In "3.1 Einführung von Stubs" wird ein Stub definiert als:
Ein Stub ist ein kontrollierbarer Ersatz für eine bestehende Abhängigkeit (oder Kollaborateur) im System. Durch die Verwendung eines Stubs können Sie Ihren Code testen, ohne ohne sich direkt mit der Abhängigkeit zu befassen.
Und definiert den Unterschied zwischen Stubs und Mocks wie folgt:
Das Wichtigste, was man sich über Mocks im Vergleich zu Stubs merken sollte, ist, dass Mocks genau wie Stubs sind, man aber gegen das Mock-Objekt assertiert, während man gegen einen Stub nicht assertiert.
Fake ist nur der Name, der sowohl für Stubs als auch für Mocks verwendet wird. Zum Beispiel, wenn Sie sich nicht um die Unterscheidung zwischen Stubs und Mocks kümmern.
Die Art und Weise, wie Osherove's zwischen Stubs und Mocks unterscheidet, bedeutet, dass jede Klasse, die als Fake für einen Test verwendet wird, sowohl ein Stub als auch ein Mock sein kann. Welche Klasse es für einen bestimmten Test ist, hängt ganz davon ab, wie Sie die Prüfungen in Ihrem Test schreiben.
- Wenn Ihr Test Werte in der zu testenden Klasse oder irgendwo anders als in der Fälschung überprüft, wurde die Fälschung als Stub verwendet. Er hat der zu testenden Klasse lediglich Werte zur Verfügung gestellt, entweder direkt durch Werte, die von Aufrufen zurückgegeben werden, oder indirekt durch das Auslösen von Seiteneffekten (in einem bestimmten Zustand) als Ergebnis von Aufrufen.
- Wenn Ihr Test die Werte der Fälschung überprüft, wurde sie als Attrappe verwendet.
Beispiel für einen Test, bei dem die Klasse FakeX als Stub verwendet wird:
const pleaseReturn5 = 5;
var fake = new FakeX(pleaseReturn5);
var cut = new ClassUnderTest(fake);
cut.SquareIt;
Assert.AreEqual(25, cut.SomeProperty);
Die fake
Instanz wird als Stub verwendet, weil die Assert
verwendet nicht fake
überhaupt nicht.
Beispiel für einen Test, bei dem die Testklasse X als Mock verwendet wird:
const pleaseReturn5 = 5;
var fake = new FakeX(pleaseReturn5);
var cut = new ClassUnderTest(fake);
cut.SquareIt;
Assert.AreEqual(25, fake.SomeProperty);
In diesem Fall ist die Assert
prüft einen Wert auf fake
und macht diese Fälschung zu einer Attrappe.
Natürlich sind diese Beispiele sehr konstruiert, aber ich sehe in dieser Unterscheidung große Vorteile. Sie macht Ihnen bewusst, wie Sie Ihre Tests durchführen und wo die Abhängigkeiten Ihrer Tests liegen.
Ich stimme mit Osherove's zu, dass
aus einer reinen Wartbarkeit Perspektive, in meinen Tests mit Mocks schafft mehr Probleme als nicht mit ihnen. Das ist meine Erfahrung, aber ich lerne immer etwas Neues.
Asserting gegen die Fälschung ist etwas, das Sie wirklich vermeiden möchten, da es Ihre Tests in hohem Maße von der Implementierung einer Klasse abhängig macht, die gar nicht die zu testende Klasse ist. Das bedeutet, dass die Tests für die Klasse ActualClassUnderTest
zu brechen beginnen kann, weil die Implementierung für ClassUsedAsMock
verändert. Und das riecht für mich sehr unangenehm. Tests für ActualClassUnderTest
sollte vorzugsweise nur dann unterbrochen werden, wenn ActualClassUnderTest
geändert wird.
Ich weiß, dass das Schreiben von Asserts gegen die Fälschung eine gängige Praxis ist, vor allem, wenn Sie eine mockist Art von TDD Teilnehmer sind. Ich schätze, ich bin fest mit Martin Fowler im klassizistischen Lager (Siehe Martin Fowlers "Mocks aren't Stubs" ) und wie Osherove Interaktionstests (die nur durch Behauptungen gegen die Fälschung durchgeführt werden können) so weit wie möglich vermeiden.
Wenn Sie wissen möchten, warum Sie Spötteleien im Sinne der Definition hier vermeiden sollten, googeln Sie nach "fowler mockist classicist". Sie werden eine Fülle von Meinungen finden.