Ich habe verschiedene Artikel über Mocking vs Stubbing in Tests gelesen, einschließlich Martin Fowlers Spötteleien sind keine Spötteleien aber ich verstehe den Unterschied immer noch nicht.
Antworten
Zu viele Anzeigen?Es gibt viele gültige Antworten, aber ich denke, es lohnt sich, dieses Formular von Onkel Bob zu erwähnen: https://8thlight.com/blog/uncle-bob/2014/05/14/TheLittleMocker.html
die beste Erklärung überhaupt mit Beispielen!
Eine Attrappe ist sowohl ein eine technische und eine funktionale Objekt.
Der Spott ist technisch . Es wird in der Tat von einer Mocking-Bibliothek (EasyMock, JMockit und neuerdings auch Mockito sind dafür bekannt) erstellt, dank Bytecode-Generierung .
Die Mock-Implementierung ist generiert in einer Weise, die es uns ermöglicht Instrument Es soll einen bestimmten Wert zurückgeben, wenn eine Methode aufgerufen wird, aber auch einige andere Dinge, wie z.B. die Überprüfung, ob eine Mock-Methode mit bestimmten Parametern (strict check) oder ohne Parameter (no strict check) aufgerufen wurde.
Instanziierung einer Attrappe :
@Mock Foo fooMock
Aufzeichnung eines Verhaltens :
when(fooMock.hello()).thenReturn("hello you!");
Überprüfen eines Aufrufs :
verify(fooMock).hello()
Dies ist eindeutig nicht die natürliche Art und Weise, die Foo-Klasse/das Foo-Verhalten zu instanziieren/überschreiben. Deshalb verweise ich auf einen technischen Aspekt.
Aber die Attrappe ist auch funktional weil sie eine Instanz der Klasse ist, die wir vom SUT isolieren müssen. Und mit aufgezeichneten Verhaltensweisen können wir sie im SUT auf die gleiche Weise verwenden wie einen Stub.
Der Stumpf ist nur eine funktionale Objekt: das ist eine Instanz der Klasse, die wir vom SUT isolieren müssen, und das ist alles. Das bedeutet, dass sowohl die Stub-Klasse als auch alle Verhaltensfixtures, die während unserer Unit-Tests benötigt werden, explizit definiert werden müssen.
Zum Beispiel zum Stub hello()
müsste die Unterklasse Foo
Klasse (oder implementiert ihre Schnittstelle, die sie hat) und zu überschreiben hello()
:
public class HelloStub extends Hello{
public String hello {
return "hello you!";
}
}
Wenn ein anderes Testszenario einen anderen Rückgabewert erfordert, müssen wir wahrscheinlich eine generische Methode zum Setzen des Rückgabewerts definieren:
public class HelloStub extends Hello{
public HelloStub(String helloReturn){
this.helloReturn = helloReturn;
}
public String hello {
return helloReturn;
}
}
Anderes Szenario: Wenn ich eine Seiteneffekt-Methode (ohne Rückgabe) hätte und überprüfen würde, ob diese Methode aufgerufen wurde, sollte ich wahrscheinlich einen Booleschen Wert oder einen Zähler in der Stub-Klasse hinzufügen, um zu zählen, wie oft die Methode aufgerufen wurde.
Schlussfolgerung
Der Stub erfordert oft viel Overhead/Code für Ihren Unit-Test. Was Mock verhindert dank der Bereitstellung von Aufzeichnungs-/Verifizierungsfunktionen out of the box.
Aus diesem Grund wird der Stub-Ansatz heutzutage in der Praxis nur noch selten verwendet, da es hervorragende Mock-Bibliotheken gibt.
Über den Artikel von Martin Fowler : Ich halte mich nicht für einen "mockistischen" Programmierer, obwohl ich Mocks verwende und Stubs vermeide.
Aber ich verwende Mock, wenn es wirklich erforderlich ist (lästige Abhängigkeiten), und ich bevorzuge Test Slicing und Mini-Integrationstests, wenn ich eine Klasse mit Abhängigkeiten teste, bei denen Mocking einen Overhead bedeuten würde.
Stummel hilft uns bei der Durchführung von Tests. Wie? Es gibt Werte, die bei der Durchführung von Tests helfen. Diese Werte sind selbst nicht real und wir haben diese Werte nur erstellt, um den Test durchzuführen. Wir erstellen zum Beispiel eine HashMap, die uns Werte liefert, die den Werten in der Datenbanktabelle ähneln. Anstatt also direkt mit der Datenbank zu interagieren, interagieren wir mit der Hashmap.
Mock ist ein Fake-Objekt, das den Test ausführt. wo wir assert.