Ich weiß, wie ich diese Begriffe verwende, aber ich frage mich, ob es akzeptierte Definitionen für Fälschung , Verspottung und Stubbing für Unit-Tests gibt. Wie definieren Sie diese für Ihre Tests? Beschreiben Sie Situationen, in denen Sie sie möglicherweise verwenden.
So benutze ich sie:
Fake : Eine Klasse, die eine Schnittstelle implementiert, aber feste Daten und keine Logik enthält. Gibt je nach Implementierung einfach "gute" oder "schlechte" Daten zurück.
Mock : Eine Klasse, die eine Schnittstelle implementiert und die Möglichkeit bietet, die Werte für die Rückgabe / Ausnahmen für bestimmte Methoden dynamisch festzulegen und zu überprüfen, ob bestimmte Methoden aufgerufen / nicht aufgerufen wurden.
Stub : Wie eine Scheinklasse, nur dass sie nicht die Möglichkeit bietet, zu überprüfen, ob Methoden aufgerufen / nicht aufgerufen wurden.
Mocks und Stubs können von Hand oder durch ein Mocking-Framework generiert werden. Gefälschte Klassen werden von Hand generiert. Ich benutze Mocks hauptsächlich, um Interaktionen zwischen meiner Klasse und abhängigen Klassen zu überprüfen. Ich verwende Stubs, sobald ich die Interaktionen überprüft habe und alternative Pfade durch meinen Code teste. Ich verwende gefälschte Klassen hauptsächlich, um Datenabhängigkeiten zu abstrahieren oder wenn Mocks / Stubs zu langwierig sind, um sie jedes Mal einzurichten.
quelle
Antworten:
Sie können einige Informationen erhalten:
Von Martin Fowler über Mock and Stub
Gefälschte Objekte haben tatsächlich funktionierende Implementierungen, verwenden jedoch normalerweise eine Verknüpfung, wodurch sie nicht für die Produktion geeignet sind
Stubs bieten vordefinierte Antworten auf Anrufe, die während des Tests getätigt wurden, und reagieren normalerweise überhaupt nicht auf etwas außerhalb der für den Test programmierten. Stubs können auch Informationen über Anrufe aufzeichnen, z. B. einen E-Mail-Gateway-Stub, der sich an die Nachrichten erinnert, die er "gesendet" hat, oder nur an die Anzahl der Nachrichten, die er "gesendet" hat.
Mocks sind das, worüber wir hier sprechen: Objekte, die mit Erwartungen vorprogrammiert sind und eine Spezifikation der Anrufe bilden, die sie voraussichtlich erhalten.
Aus xunitpattern :
Fake : Wir erwerben oder erstellen eine sehr einfache Implementierung derselben Funktionalität, die von einer Komponente bereitgestellt wird, von der das SUT abhängt, und weisen das SUT an, sie anstelle der realen zu verwenden.
Stub : Diese Implementierung ist so konfiguriert, dass sie auf Aufrufe vom SUT mit den Werten (oder Ausnahmen) reagiert, die den nicht getesteten Code (siehe Produktionsfehler auf Seite X) innerhalb des SUT ausführen. Eine wichtige Anzeige für die Verwendung eines Teststubs ist der nicht getestete Code, der durch die Unfähigkeit verursacht wird, die indirekten Eingaben des SUT zu steuern
Mock-Objekt , das dieselbe Schnittstelle implementiert wie ein Objekt, von dem das SUT (System Under Test) abhängt. Wir können ein Mock-Objekt als Beobachtungspunkt verwenden, wenn wir eine Verhaltensüberprüfung durchführen müssen, um zu vermeiden, dass eine nicht getestete Anforderung (siehe Produktionsfehler auf Seite X) auftritt, die durch die Unfähigkeit verursacht wird, Nebenwirkungen des Aufrufens von Methoden auf dem SUT zu beobachten.
Persönlich
Ich versuche zu vereinfachen, indem ich: Mock and Stub benutze. Ich verwende Mock, wenn es sich um ein Objekt handelt, das einen Wert zurückgibt, der auf die getestete Klasse festgelegt ist. Ich verwende Stub, um eine zu testende Interface- oder Abstract-Klasse nachzuahmen. Tatsächlich spielt es keine Rolle, wie Sie es nennen, es sind alles Klassen, die nicht in der Produktion verwendet werden und als Dienstprogrammklassen zum Testen verwendet werden.
quelle
Stub - ein Objekt, das vordefinierte Antworten auf Methodenaufrufe liefert.
Mock - ein Objekt, an das Sie Erwartungen setzen.
Fake - ein Objekt mit eingeschränkten Funktionen (zu Testzwecken), z. B. ein gefälschter Webdienst.
Test Double ist der allgemeine Begriff für Stubs, Mocks und Fakes. Aber informell hört man oft Leute, die sie einfach Spott nennen.
quelle
EXPECT_CALL()
einer verspotteten Methode s erstellen können, die bestimmte Ausgaben basierend auf bestimmten Eingaben erzwingen, indem Sie den Typ.WillOnce(Invoke(my_func_or_lambda_func))
(oder mit.WillRepeatedly()
) verwenden Syntax an eineEXPECT_CALL()
. Einige Beispiele für die VerwendungInvoke()
finden Sie in einem anderen Kontext am Ende meiner langen Antwort hier: stackoverflow.com/a/60905880/4561887 .Invoke()
hier: github.com/google/googletest/blob/master/googlemock/docs/… . Wie auch immer, die Schlussfolgerung lautet: Mit Google Mock (gmock) können auf einfache Weise sowohl Mocks als auch Stubs erstellt werden , obwohl die meisten Mocks keine Stubs sind.Ich bin überrascht, dass es diese Frage schon so lange gibt und noch niemand eine Antwort auf Roy Osheroves "The Art of Unit Testing" gegeben hat .
In "3.1 Einführung von Stubs" wird ein Stub wie folgt definiert:
Und definiert den Unterschied zwischen Stubs und Mocks als:
Fake ist nur der Name, der sowohl für Stubs als auch für Mocks verwendet wird. Zum Beispiel, wenn Sie sich nicht für die Unterscheidung zwischen Stubs und Mocks interessieren.
Die Art und Weise, wie Osherove zwischen Stubs und Mocks unterscheidet, bedeutet, dass jede Klasse, die als Fälschung zum Testen verwendet wird, sowohl ein Stub als auch ein Mock sein kann. Was es für einen bestimmten Test ist, hängt ganz davon ab, wie Sie die Schecks in Ihren Test schreiben.
Beispiel eines Tests, bei dem die Klasse FakeX als Stub verwendet wird:
Die
fake
Instanz wird als Stub verwendet, da sieAssert
überhaupt nicht verwendet wirdfake
.Beispiel eines Tests, bei dem die Testklasse X als Schein verwendet wird:
In diesem Fall
Assert
überprüft das einen Wert auffake
, wodurch diese Fälschung zu einem Schein wird.Natürlich sind diese Beispiele sehr erfunden, aber ich sehe großen Wert in dieser Unterscheidung. Es macht Sie darauf aufmerksam, wie Sie Ihre Daten testen und wo die Abhängigkeiten Ihres Tests liegen.
Ich stimme dem von Osherove zu
Die Behauptung gegen die Fälschung ist etwas, das Sie wirklich vermeiden möchten, da Ihre Tests in hohem Maße von der Implementierung einer Klasse abhängen, die überhaupt nicht getestet wird. Dies bedeutet, dass die Tests für die Klasse
ActualClassUnderTest
unterbrochen werden können, da sich die Implementierung fürClassUsedAsMock
geändert hat. Und das riecht übel nach mir. Tests fürActualClassUnderTest
sollten vorzugsweise nur dann unterbrochen werden, wenn sieActualClassUnderTest
geändert werden.Mir ist klar, dass das Schreiben von Behauptungen gegen die Fälschung eine gängige Praxis ist, insbesondere wenn Sie ein spöttischer TDD-Abonnent sind. Ich glaube, ich bin fest mit Martin Fowler im Lager der Klassiker verbunden (siehe Martin Fowlers "Mocks are not Stubs" ) und vermeide wie Osherove Interaktionstests (die nur durch Behauptung gegen die Fälschung durchgeführt werden können) so weit wie möglich.
Zum Spaß beim Lesen, warum Sie Verspottungen wie hier definiert vermeiden sollten, googeln Sie nach "Fowler Mockist Classicist". Sie finden eine Vielzahl von Meinungen.
quelle
Wie in der Antwort mit den meisten Stimmen erwähnt, erörtert Martin Fowler diese Unterscheidungen in Mocks Aren't Stubs und insbesondere in der Unterüberschrift Der Unterschied zwischen Mocks und Stubs. Lesen Sie daher unbedingt diesen Artikel.
Anstatt sich darauf zu konzentrieren, wie sich diese Dinge unterscheiden, finde ich es aufschlussreicher, sich darauf zu konzentrieren, warum dies unterschiedliche Konzepte sind. Jedes existiert für einen anderen Zweck.
Fälschungen
Eine Fälschung ist eine Implementierung, die sich "natürlich" verhält, aber nicht "echt" ist. Dies sind unscharfe Konzepte, und so haben verschiedene Menschen unterschiedliche Vorstellungen davon, was Dinge zu einer Fälschung macht.
Ein Beispiel für eine Fälschung ist eine speicherinterne Datenbank (z. B. die Verwendung von SQLite mit dem
:memory:
Speicher). Sie würden dies niemals für die Produktion verwenden (da die Daten nicht beibehalten werden), aber es ist als Datenbank für die Verwendung in einer Testumgebung vollkommen ausreichend. Es ist auch viel leichter als eine "echte" Datenbank.Als weiteres Beispiel verwenden Sie möglicherweise eine Art Objektspeicher (z. B. Amazon S3) in der Produktion, aber in einem Test können Sie Objekte einfach in Dateien auf der Festplatte speichern. dann wäre Ihre Implementierung "Auf Festplatte speichern" eine Fälschung. (Oder Sie können sogar den Vorgang "Auf Festplatte speichern" vortäuschen, indem Sie stattdessen ein In-Memory-Dateisystem verwenden.)
Stellen Sie sich als drittes Beispiel ein Objekt vor, das eine Cache-API bereitstellt. Ein Objekt, das die richtige Schnittstelle implementiert, aber einfach überhaupt kein Caching durchführt, sondern immer einen Cache-Fehler zurückgibt, wäre eine Art Fälschung.
Der Zweck einer Fälschung besteht nicht darin, das Verhalten des zu testenden Systems zu beeinflussen , sondern die Implementierung des Tests zu vereinfachen (indem unnötige oder schwergewichtige Abhängigkeiten beseitigt werden).
Stubs
Ein Stub ist eine Implementierung, die sich "unnatürlich" verhält. Es ist vorkonfiguriert (normalerweise vom Testaufbau), um auf bestimmte Eingaben mit bestimmten Ausgaben zu reagieren.
Der Zweck eines Stubs besteht darin, Ihr zu testendes System in einen bestimmten Zustand zu versetzen. Zum Beispiel, wenn Sie einen Test für einige Code schreiben , dass wirkt mit einer REST - API, könnten Sie Stub die REST - API mit einer API , dass immer eine Dosen-Antwort zurückgibt, oder dass reagiert auf eine API - Anforderung mit einem bestimmten Fehler. Auf diese Weise können Sie Tests schreiben, die Aussagen darüber machen, wie das System auf diese Zustände reagiert. Testen Sie beispielsweise die Antwort, die Ihre Benutzer erhalten, wenn die API einen 404-Fehler zurückgibt.
Ein Stub wird normalerweise implementiert, um nur auf die genauen Interaktionen zu reagieren, auf die Sie ihn angewiesen haben. Aber das Hauptmerkmal, das etwas zu einem Stub macht, ist sein Zweck : Bei einem Stub geht es darum, Ihren Testfall einzurichten.
Verspottet
Ein Mock ähnelt einem Stub, es wurde jedoch eine Überprüfung hinzugefügt. Der Zweck eines Mocks besteht darin, Aussagen darüber zu treffen, wie Ihr zu testendes System mit der Abhängigkeit interagiert .
Zum Beispiel, wenn Sie einen Test für ein System , dass Uploads von Dateien auf eine Website schreiben, könnten Sie einen bauen Mock , der eine Datei akzeptiert und dass Sie behaupten können , dass die hochgeladene Datei korrekt war. In kleinerem Maßstab wird häufig ein Mock eines Objekts verwendet, um zu überprüfen, ob das zu testende System bestimmte Methoden des verspotteten Objekts aufruft.
Mocks sind an Interaktionstests gebunden , bei denen es sich um eine spezifische Testmethode handelt. Menschen, die lieber den Systemstatus als die Systeminteraktionen testen möchten, werden Mocks, wenn überhaupt, sparsam einsetzen.
Test verdoppelt sich
Fälschungen, Stubs und Mocks gehören zur Kategorie der Testdoppel . Ein Testdouble ist ein Objekt oder System, das Sie in einem Test anstelle von etwas anderem verwenden. Bei den meisten automatisierten Softwaretests werden Testdoppel der einen oder anderen Art verwendet. Einige andere Arten von Test-Doubles umfassen Dummy-Werte , Spione und E / A- Blackholes .
quelle
Um die Verwendung von Stubs und Mocks zu veranschaulichen, möchte ich auch ein Beispiel hinzufügen, das auf Roy Osheroves " The Art of Unit Testing " basiert .
Stellen Sie sich vor, wir haben eine LogAnalyzer-Anwendung, die die einzige Funktionalität zum Drucken von Protokollen bietet. Es muss nicht nur mit einem Webdienst kommunizieren, sondern wenn der Webdienst einen Fehler auslöst, muss LogAnalyzer den Fehler in einer anderen externen Abhängigkeit protokollieren und per E-Mail an den Webdienstadministrator senden.
Hier ist die Logik, die wir in LogAnalyzer testen möchten:
Wie testen Sie, ob LogAnalyzer den E-Mail-Dienst korrekt aufruft, wenn der Webdienst eine Ausnahme auslöst? Hier sind die Fragen, mit denen wir konfrontiert sind:
Wie können wir den Webdienst ersetzen?
Wie können wir eine Ausnahme vom Webdienst simulieren, um den Anruf beim E-Mail-Dienst zu testen?
Woher wissen wir, dass der E-Mail-Dienst korrekt oder überhaupt aufgerufen wurde?
Wir können die ersten beiden Fragen beantworten, indem wir einen Stub für den Webdienst verwenden . Um das dritte Problem zu lösen, können wir ein Scheinobjekt für den E-Mail-Dienst verwenden .
Eine Fälschung ist ein Oberbegriff, der verwendet werden kann, um entweder einen Stub oder einen Mock zu beschreiben. In unserem Test haben wir zwei Fälschungen. Eine davon ist der E-Mail-Dienst-Mock, mit dem wir überprüfen, ob die richtigen Parameter an den E-Mail-Dienst gesendet wurden. Der andere ist ein Stub, mit dem wir eine vom Webdienst ausgelöste Ausnahme simulieren. Es ist ein Stub, weil wir den gefälschten Webdienst nicht verwenden, um das Testergebnis zu überprüfen, sondern nur um sicherzustellen, dass der Test korrekt ausgeführt wird. Der E-Mail-Dienst ist ein Schein, weil wir dagegen behaupten werden, dass er korrekt aufgerufen wurde.
quelle
Das, was Sie darauf behaupten, wird als Scheinobjekt bezeichnet , und alles andere, was gerade zum Testlauf beigetragen hat, ist ein Stub .
quelle
Es geht darum, die Tests ausdrucksstark zu machen. Ich setze Erwartungen an einen Mock, wenn der Test eine Beziehung zwischen zwei Objekten beschreiben soll. Ich stoppe Rückgabewerte, wenn ich ein unterstützendes Objekt einrichte, um zu dem interessanten Verhalten im Test zu gelangen.
quelle
Wenn Sie mit Arrange-Act-Assert vertraut sind, besteht eine Möglichkeit, den für Sie nützlichen Unterschied zwischen Stub und Mock zu erklären, darin, dass Stubs zum Arrangierabschnitt gehören, da sie zum Anordnen des Eingabestatus dienen und Mocks dazu gehören den Assert-Abschnitt, wie er zum Durchsetzen von Ergebnissen dient.
Dummies machen nichts. Sie dienen nur zum Ausfüllen von Parameterlisten, damit Sie keine undefinierten oder Null-Fehler erhalten. Sie sind auch vorhanden, um die Typprüfung in streng typisierten Sprachen zu erfüllen, sodass Sie kompilieren und ausführen können.
quelle
Stub, Fakes und Mocks haben unterschiedliche Bedeutungen in verschiedenen Quellen. Ich empfehle Ihnen, die internen Begriffe Ihres Teams vorzustellen und deren Bedeutung zu vereinbaren.
Ich denke, es ist wichtig, zwischen zwei Ansätzen zu unterscheiden: - Verhaltensvalidierung (impliziert Verhaltenssubstitution) - Endzustandsvalidierung (impliziert Verhaltensemulation)
Im Fehlerfall sollten Sie eine E-Mail senden. Bei der Verhaltensüberprüfung überprüfen Sie, ob die Methode
Send
vonIEmailSender
einmal ausgeführt wurde. Und Sie müssen das Rückgabeergebnis dieser Methode emulieren und die ID der gesendeten Nachricht zurückgeben. Sie sagen also: "Ich gehe davon aus, dassSend
dies aufgerufen wird. Und ich werde für jeden Anruf nur eine Dummy-ID (oder eine zufällige ID) zurückgeben . " Dies ist eine Verhaltensüberprüfung:emailSender.Expect(es=>es.Send(anyThing)).Return((subject,body) => "dummyId")
Wenn Sie eine Statusüberprüfung durchführen, müssen Sie
TestEmailSender
diese Implementierungen erstellenIEmailSender
. Und implementieren Sie dieSend
Methode - indem Sie Eingaben in einer Datenstruktur speichern, die für die zukünftige Statusüberprüfung verwendet wird, z. B. ein Array einiger Objekte,SentEmails
und dann testen, ob Sie dieSentEmails
erwartete E-Mail enthalten. Dies ist eine Zustandsüberprüfung:Assert.AreEqual(1, emailSender.SentEmails.Count)
Aus meinen Lesungen ging hervor, dass die Verhaltensvalidierung normalerweise als Mocks bezeichnet wird . Und die Zustandsvalidierung wird normalerweise als Stubs oder Fakes bezeichnet .
quelle
Stub und Fake sind Objekte, da sie ihre Reaktion basierend auf Eingabeparametern variieren können. Der Hauptunterschied zwischen ihnen besteht darin, dass ein Fake einer realen Implementierung näher kommt als ein Stub. Stubs enthalten grundsätzlich fest codierte Antworten auf eine erwartete Anfrage. Sehen wir uns ein Beispiel an:
Ein Mock ist ein Schritt nach oben von Fälschungen und Stubs. Mocks bieten die gleiche Funktionalität wie Stubs, sind jedoch komplexer. Für sie können Regeln definiert werden, die festlegen, in welcher Reihenfolge Methoden in ihrer API aufgerufen werden müssen. Die meisten Mocks können nachverfolgen, wie oft eine Methode aufgerufen wurde, und anhand dieser Informationen reagieren. Mocks kennen im Allgemeinen den Kontext jedes Anrufs und können in verschiedenen Situationen unterschiedlich reagieren. Aus diesem Grund erfordern Mocks einige Kenntnisse der Klasse, die sie verspotten. Ein Stub kann im Allgemeinen nicht verfolgen, wie oft eine Methode aufgerufen wurde oder in welcher Reihenfolge eine Folge von Methoden aufgerufen wurde. Ein Mock sieht aus wie:
quelle
fake object
ist eine echte Implementierung der Schnittstelle (Protokoll) oder eine Erweiterung unter Verwendung von Vererbung oder anderen Ansätzen, die zum Erstellen verwendet werden können - ist Abhängigkeit. Normalerweise wird es vom Entwickler als einfachste Lösung erstellt, um einige Abhängigkeiten zu ersetzenstub object
ist ein nacktes Objekt (0, nil und Methoden ohne Logik) mit einem zusätzlichen und vordefinierten (vom Entwickler) Status , um zurückgegebene Werte zu definieren. Normalerweise wird es vom Framework erstelltmock object
ist sehr ähnlich,stub object
aber der zusätzliche Status wird während der Programmausführung geändert, um zu überprüfen, ob etwas passiert ist (Methode wurde aufgerufen).quelle