Was ist der Unterschied zwischen einem Mock & Stub?


963

Ich habe verschiedene Artikel über Spott und Stubbing beim Testen gelesen, darunter Martin Fowlers Mocks Aren't Stubs , verstehe aber den Unterschied immer noch nicht.



75
@OP Weil es keinen Unterschied gibt. Dieser Artikel, so sehr er auch von der Community geliebt wird, macht - bei allem Respekt - alles unnötig verwirrend, indem er Wörtern, die ansonsten leicht zu verstehen sind, zusätzliche Bedeutung verleiht und Dinge unnötig kompliziert macht. Mock ist nur ein Mock, etwas, das eine gefälschte Geschäftslogik anstelle einer echten ausführt. Am Ende nach Verhalten zu suchen, ist Ihre Wahl, aber es ist immer noch ein Schein. Oder wie auch immer du es nennen willst, aber mach es EINS. Haare nicht spalten. Halten Sie es einfach, damit die Leute Ihr Konzept leicht verstehen können - der obige Artikel schlägt fehl.
wst

10
"Die Klassifizierung zwischen Mocks, Fakes und Stubs ist in der Literatur sehr inkonsistent." Mit vielen Zitaten. Immer noch eines meiner Lieblingszitate von Wikipedia - falls es so etwas gibt :) en.wikipedia.org/wiki/Mock_object
JD.

11
dass Martin Fowlers Artikel für Anfänger wirklich schwer zu verstehen ist.
lmiguelvargasf

1
Ich verstehe es so, dass ein Stub nur ein Wegwerfobjekt für Ihren Test ist, wie eine Sammlung von Dummy-Daten. Ein Mock wäre eine geschickt überschriebene Version von etwas Komplexerem, wie einer Service-Schicht mit verschiedenen Methoden, deren Verhalten Sie möglicherweise für Ihre Tests geändert haben. Die beiden Dinge werden zusammen verwendet, als könnten Sie einige stoppelige Objekte in Ihre verspottete Ebene einführen.
JsonStatham

Antworten:


746

Stub

Ich glaube, der größte Unterschied ist, dass ein Stub, den Sie bereits mit vorbestimmtem Verhalten geschrieben haben. Sie hätten also eine Klasse, die die Abhängigkeit (abstrakte Klasse oder Schnittstelle höchstwahrscheinlich) implementiert, die Sie zu Testzwecken vortäuschen, und die Methoden würden nur mit festgelegten Antworten ausgeblendet. Sie würden nichts Besonderes tun und Sie hätten den gestoppelten Code dafür bereits außerhalb Ihres Tests geschrieben.

Spotten

Ein Mock ist etwas, das Sie im Rahmen Ihres Tests mit Ihren Erwartungen einrichten müssen. Ein Mock wird nicht auf eine vorgegebene Weise eingerichtet, sodass Sie Code haben, der dies in Ihrem Test ausführt. Mocks werden in gewisser Weise zur Laufzeit festgelegt, da der Code, der die Erwartungen festlegt, ausgeführt werden muss, bevor sie etwas tun.

Unterschied zwischen Mocks und Stubs

Mit Mocks geschriebene Tests folgen normalerweise einem initialize -> set expectations -> exercise -> verifyTestmuster. Während der vorab geschriebene Stub einem folgen würde initialize -> exercise -> verify.

Ähnlichkeit zwischen Mocks und Stubs

Der Zweck von beiden besteht darin, das Testen aller Abhängigkeiten einer Klasse oder Funktion zu eliminieren, damit Ihre Tests fokussierter und einfacher in dem sind, was sie zu beweisen versuchen.


876

Vorwort

Es gibt verschiedene Definitionen von Objekten, die nicht real sind. Der allgemeine Begriff ist Testdoppel . Dieser Begriff umfasst: Dummy , Fake , Stub , Mock .

Referenz

Nach Martin Fowlers Artikel :

  • Dummy- Objekte werden herumgereicht, aber nie benutzt. Normalerweise werden sie nur zum Füllen von Parameterlisten verwendet.
  • Gefälschte Objekte haben tatsächlich funktionierende Implementierungen, verwenden jedoch normalerweise eine Verknüpfung, die sie für die Produktion nicht geeignet macht (eine In-Memory-Datenbank ist ein gutes Beispiel).
  • 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.

Stil

Mocks vs Stubs = Verhaltenstests vs Zustandstests

Prinzip

Nach dem Prinzip des Tests kann nur eine Sache pro Test mehrere Stubs in einem Test enthalten, aber im Allgemeinen gibt es nur einen Schein.

Lebenszyklus

Testlebenszyklus mit Stubs:

  1. Setup - Bereiten Sie das zu testende Objekt und seine Stubs-Mitarbeiter vor.
  2. Übung - Testen Sie die Funktionalität.
  3. Status überprüfen - Verwenden Sie Asserts, um den Status des Objekts zu überprüfen.
  4. Teardown - Ressourcen bereinigen.

Testlebenszyklus mit Mocks:

  1. Setup-Daten - Bereiten Sie das zu testende Objekt vor.
  2. Erwartungen einrichten - Bereiten Sie Erwartungen in einem Modell vor, das vom primären Objekt verwendet wird.
  3. Übung - Testen Sie die Funktionalität.
  4. Erwartungen überprüfen - Stellen Sie sicher, dass im Mock die richtigen Methoden aufgerufen wurden.
  5. Status überprüfen - Verwenden Sie Asserts, um den Status des Objekts zu überprüfen.
  6. Teardown - Ressourcen bereinigen.

Zusammenfassung

Sowohl Mocks- als auch Stubs-Tests geben eine Antwort auf die Frage: Was ist das Ergebnis?

Tests mit Mocks interessieren sich auch für: Wie wurde das Ergebnis erzielt?


Warten Sie, Mocks geben auch eingemachte Antworten zurück? Denn sonst warum beantworten sie die Frage?
AturSams

Aus dem, was Sie geschrieben haben, kann ich sagen, dass Mocks = Stubs + Erwartungen und Überprüfungen sind, da Mocks "vordefinierte Antworten auf Anrufe liefern, die während des Tests getätigt wurden und normalerweise überhaupt nicht auf etwas reagieren, das nicht für den Test programmiert ist" (wie Stubs). Und ein Beispiel, das Fowler als Beispiel für einen Stummel zeigte, ist tatsächlich ein Beispiel für einen Spion! Das bedeutet, dass ein Mock ein Stummel ist und ein Spion ein Stummel. Und ein Stub ist nur ein Objekt mit mehreren Arbeitsmethoden. Dies erklärt auch, warum Mockito die stub () -Methode nicht mehr unterstützt.
Kolobok

Was mich daran verwirrt und die akzeptierte Antwort ist diese „Erwartungseinstellung“, was bedeutet das überhaupt? Normalerweise erstellen Sie im „Hauptcode“ die Ergebnisse, die Sie erwarten würden. Es hört sich so an, als würden Sie die Erwartungen irgendwie in das Scheinobjekt einbringen, was für mich keinen Sinn ergibt. AUCH Sie können den Mock genauso einfach mit einigen Eingaben üben, das Ergebnis speichern, später „die Erwartungen“ erstellen und dann vergleichen. Sie verwenden eine Terminologie, die ich zu abstrakt und mehrdeutig finde.
IceFire

365

Ein Stub ist ein einfaches falsches Objekt. Es stellt nur sicher, dass der Test reibungslos verläuft.
Ein Mock ist ein schlauerer Stummel. Sie überprüfen, ob Ihr Test erfolgreich ist.


33
Ich denke, dies ist die prägnanteste und genaueste Antwort. Imbiss: ein nachgebildeter IS-A-Stummel. stackoverflow.com/a/17810004/2288628 ist die längere Version dieser Antwort.
PoweredByRice

8
Ich denke nicht, dass ein Mock ein Stummel ist. Mocks werden zum Bestätigen verwendet und sollten niemals Daten zurückgeben. Stubs werden zum Zurückgeben von Daten verwendet und sollten niemals Daten zurückgeben.
Dave1010

2
@ dave1010 Mocks können definitiv Daten zurückgeben oder sogar eine Ausnahme auslösen. Sie sollten dies als Reaktion auf die an sie übergebenen Parameter tun.
Trenton

2
@trenton Wenn ein Objekt basierend auf übergebenen Daten zurückgegeben oder ausgelöst wird, handelt es sich um eine Fälschung und nicht um eine Fälschung . Stubs testen, wie Ihr SUT Nachrichten empfängt , Mocks testen, wie Ihr SUT Nachrichten sendet . Das Verwechseln der 2 führt wahrscheinlich zu einem schlechten OO-Design.
Dave1010

8
Ich finde das großartig - ein Stub gibt Antworten auf Fragen zurück. Ein Mock gibt auch Antworten auf Fragen zurück (is-a stub), überprüft aber auch, ob die Frage gestellt wurde !!
Leif

238

Hier ist eine Beschreibung von jedem, gefolgt von einem Beispiel aus der realen Welt.

  • Dummy - nur falsche Werte, um die zu befriedigen API.

    Beispiel : Wenn Sie eine Methode einer Klasse testen, für die viele obligatorische Parameter in einem Konstruktor erforderlich sind, die sich nicht auf Ihren Test auswirken , können Sie Dummy-Objekte erstellen, um neue Instanzen einer Klasse zu erstellen.

  • Fake - Erstellen Sie eine Testimplementierung einer Klasse, die möglicherweise von einer externen Infrastruktur abhängig ist. (Es wird empfohlen, dass Ihr Komponententest NICHT mit der externen Infrastruktur interagiert.)

    Beispiel : Erstellen Sie eine gefälschte Implementierung für den Zugriff auf eine Datenbank und ersetzen Sie sie durch eine in-memorySammlung.

  • Stub - Override-Methoden zur Rückgabe fest codierter Werte, auch als bezeichnet state-based.

    Beispiel : Ihre Testklasse hängt von einer Methode ab Calculate(), deren Abschluss 5 Minuten dauert. Anstatt 5 Minuten zu warten, können Sie die eigentliche Implementierung durch einen Stub ersetzen, der fest codierte Werte zurückgibt. nur einen kleinen Bruchteil der Zeit in Anspruch nehmen.

  • Mock - sehr ähnlich, Stubaber interaction-basednicht staatlich. Dies bedeutet, dass Sie nicht erwarten Mock, einen Wert zurückzugeben, sondern davon ausgehen, dass eine bestimmte Reihenfolge der Methodenaufrufe erfolgt.

    Beispiel: Sie testen eine Benutzerregistrierungsklasse. Nach dem Anruf Savesollte es anrufen SendConfirmationEmail.

Stubsund Mockssind eigentlich Untertypen von Mock, beide tauschen echte Implementierung mit Testimplementierung aus, aber aus unterschiedlichen, spezifischen Gründen.


175

Im codeschool.com- Kurs Rails Testing for Zombies geben sie diese Definition der Begriffe an:

Stub

Zum Ersetzen einer Methode durch Code, der ein angegebenes Ergebnis zurückgibt.

Spotten

Ein Stub mit der Behauptung, dass die Methode aufgerufen wird.

Wie Sean Copenhaver in seiner Antwort beschrieben hat, besteht der Unterschied darin, dass Verspottungen Erwartungen setzen (dh Aussagen darüber machen, ob oder wie sie angerufen werden).


Um Dillon Post zu ergänzen, denken Sie darüber nach, Sie haben eine Klasse namens "MakeACake", die mehrere Bibliotheken nimmt: Milch, Eier, Zucker, Ofen.
Aarkerio

139

Stubs bestehen Ihre Tests nicht, Mock kann.


2
Und ich denke, das ist gut, Sie wissen, ob Tests nach dem Refactoring das gleiche Verhalten haben.
RodriKing

1
@ RodriKing Ich habe das gleiche Gefühl. Wie bei Mock haben Sie bei Änderungen im Produktionscode entsprechende Änderungen am Testcode. Welches ist Schmerz! Bei Stubs scheint es so, als würden Sie das Verhalten ständig testen, sodass mit dem Testcode keine Mikroänderungen vorgenommen werden müssen.
Tucq88

35

Ich denke, die einfachste und klarere Antwort auf diese Frage gibt Roy Osherove in seinem Buch The art of Unit Testing (Seite 85).

Der einfachste Weg, um festzustellen, dass es sich um einen Stub handelt, besteht darin, festzustellen, dass der Stub den Test niemals nicht bestehen kann. Die Behauptungen, die der Test verwendet, richten sich immer gegen die zu testende Klasse.

Andererseits verwendet der Test ein Scheinobjekt, um zu überprüfen, ob der Test fehlgeschlagen ist oder nicht. [...]

Auch hier ist das Scheinobjekt das Objekt, mit dem wir prüfen, ob der Test fehlgeschlagen ist oder nicht.

Das heißt, wenn Sie Behauptungen gegen die Fälschung aufstellen, bedeutet dies, dass Sie die Fälschung als Schein verwenden. Wenn Sie die Fälschung nur verwenden, um den Test ohne Behauptung darüber durchzuführen, verwenden Sie die Fälschung als Stub.


2
Ich wünschte, Ihre Antwort würde ihren Weg nach oben finden. Hier erklärt R. Osherove dies youtu.be/fAb_OnooCsQ?t=1006 .
Michael Ekoka

31

Lassen Sie mich versuchen, alle obigen Erklärungen zusammenzufassen:

  • Stub : Ein Dummy-Code, mit dem der Test ausgeführt werden kann, aber es ist Ihnen egal, was damit passiert.
  • Mock : Ein Dummy-Code, den Sie VERIFIZIEREN, wird im Rahmen des Tests korrekt aufgerufen.
  • Spy : Ein Dummy-Code, der einige Aufrufe eines echten Codes abfängt und es Ihnen ermöglicht, Anrufe zu überprüfen, ohne das gesamte ursprüngliche Objekt zu ersetzen.

4
Gute Antwort. Mock klingt jedoch ziemlich ähnlich wie Spy, basierend auf Ihrer Definition. Wäre schön, wenn Sie Ihre Antwort mit ein paar weiteren Testdoppeln aktualisieren würden.
Rowan Gontier

Ich hatte noch nie von Spy gehört, als ich diese Antwort schrieb.
O'Rooney

23

Ein Mock testet nur das Verhalten und stellt sicher, dass bestimmte Methoden aufgerufen werden. Ein Stub ist eine testbare Version (per se) eines bestimmten Objekts.

Was meinst du mit Apple?


19
"Was meinst du mit Apple?" Verwenden Sie Helvetica
Kubi

7
Auf Apple-Art und nicht auf Microsoft-Art :)
never_had_a_name

2
Hilft das der Situation?
NebulaFox

21

Wenn Sie es mit dem Debuggen vergleichen:

Stub ist so, als würde man sicherstellen, dass eine Methode den richtigen Wert zurückgibt

Mock ist so, als würde man tatsächlich in die Methode eintreten und sicherstellen, dass alles im Inneren korrekt ist, bevor der richtige Wert zurückgegeben wird.


20

Die Verwendung eines mentalen Modells hat mir wirklich geholfen, dies zu verstehen, und nicht alle Erklärungen und Artikel, die nicht ganz "eingedrungen" sind.

Stellen Sie sich vor, Ihr Kind hat eine Glasplatte auf dem Tisch und beginnt damit zu spielen. Jetzt hast du Angst, dass es kaputt geht. Also gibst du ihm stattdessen eine Plastikplatte. Das wäre ein Mock (gleiches Verhalten, gleiche Schnittstelle, "weichere" Implementierung).

Angenommen, Sie haben keinen Plastikersatz, und Sie erklären: "Wenn Sie weiter damit spielen, wird es kaputt gehen!". Das ist ein Stub , Sie haben im Voraus einen vordefinierten Status angegeben.

Ein Dummy wäre die Gabel, die er nicht einmal benutzt hat ... und ein Spion könnte so etwas wie die gleiche Erklärung sein, die Sie bereits benutzt haben und die funktioniert hat.


19

Ich denke, der wichtigste Unterschied zwischen ihnen sind ihre Absichten.

Lassen Sie mich versuchen, es in WARUM Stummel vs. WARUM Mock zu erklären

Angenommen, ich schreibe Testcode für den öffentlichen Timeline-Controller meines Mac-Twitter-Clients

Hier ist ein Testbeispielcode

twitter_api.stub(:public_timeline).and_return(public_timeline_array)
client_ui.should_receive(:insert_timeline_above).with(public_timeline_array)
controller.refresh_public_timeline
  • STUB: Die Netzwerkverbindung zur Twitter-API ist sehr langsam, was meinen Test langsam macht. Ich weiß, dass es Zeitleisten zurückgibt, deshalb habe ich einen Stub erstellt, der die HTTP-Twitter-API simuliert, damit mein Test ihn sehr schnell ausführt und ich den Test auch dann ausführen kann, wenn ich offline bin.
  • MOCK: Ich habe noch keine meiner UI-Methoden geschrieben und bin mir nicht sicher, welche Methoden ich für mein UI-Objekt schreiben muss. Ich hoffe zu wissen, wie mein Controller mit meinem UI-Objekt zusammenarbeitet, indem ich den Testcode schreibe.

Indem Sie Mock schreiben, ermitteln Sie die Beziehung zur Objektzusammenarbeit, indem Sie überprüfen, ob die Erwartungen erfüllt sind, während Stub nur das Verhalten des Objekts simuliert.

Ich schlage vor, diesen Artikel zu lesen, wenn Sie mehr über Mocks erfahren möchten: http://jmock.org/oopsla2004.pdf


1
Ich denke, Sie haben die richtige Idee, aber Dillon Kearns hat sie viel klarer erklärt.
O'Rooney

19

Um ganz klar und praktisch zu sein:

Stub: Eine Klasse oder ein Objekt, das die Methoden der zu fälschenden Klasse / des zu fälschenden Objekts implementiert und immer das zurückgibt, was Sie möchten.

Beispiel in JavaScript:

var Stub = {
   method_a: function(param_a, param_b){
      return 'This is an static result';
   }
}

Mock: Das Gleiche gilt für stub, fügt jedoch eine Logik hinzu, die beim Aufrufen einer Methode "überprüft", sodass Sie sicher sein können, dass eine Implementierung diese Methode aufruft.

Stellen Sie sich als Beispiel vor, dass Sie eine Benutzerregistrierungsklasse testen, wie @mLevan sagt. Nach dem Aufruf von Save sollte SendConfirmationEmail aufgerufen werden.

Ein sehr dummer Code Beispiel:

var Mock = {
   calls: {
      method_a: 0
   }

   method_a: function(param_a, param_b){
     this.method_a++; 
     console.log('Mock.method_a its been called!');
   }
}

16

Diese Folie erklärt die Hauptunterschiede sehr gut.

Geben Sie hier die Bildbeschreibung ein

* Aus CSE 403 Lecture 16, University of Washington (Folie erstellt von "Marty Stepp")


Dies ist die klarere Erklärung des Unterschieds zwischen den beiden, IMO. Für Stub: Der Tester nimmt den Stub und verwendet ihn direkt in der zu testenden Klasse. Für Mock muss der Tester jedoch festlegen, wie das Mock-Objekt verwendet wird. In verschiedenen Fällen verhält es sich unterschiedlich. Im Gegensatz dazu wird nicht erwartet, dass sich Stub anders verhält, sondern wie er ist (was bedeutet, dass bei jeder Kontaktaufnahme dieselben Daten zurückgegeben werden)
Dexter

12

Ich mag die Erklärung von Roy Osherove [ Videolink ] .

Jede erstellte Klasse oder jedes erstellte Objekt ist eine Fälschung. Es ist ein Mock, wenn Sie Anrufe dagegen überprüfen. Ansonsten ist es ein Stummel.


12
  • Stubs vs. Mocks
    • Stubs
      1. Geben Sie spezifische Antworten auf Methodenaufrufe
        • Beispiel: myStubbedService.getValues ​​() gibt nur einen String zurück, der vom zu testenden Code benötigt wird
      2. Wird vom zu testenden Code verwendet, um ihn zu isolieren
      3. Test kann nicht fehlschlagen
        • Beispiel: myStubbedService.getValues ​​() gibt nur den Stubbed-Wert zurück
      4. implementieren oft abstrakte Methoden
    • Verspottet
      1. "Obermenge" von Stubs; kann behaupten, dass bestimmte Methoden aufgerufen werden
        • Beispiel: Stellen Sie sicher, dass myMockedService.getValues ​​() nur einmal aufgerufen wird
      2. wird verwendet, um das Verhalten des zu testenden Codes zu testen
      3. kann Test nicht bestehen
        • Beispiel: Stellen Sie sicher, dass myMockedService.getValues ​​() einmal aufgerufen wurde. Die Überprüfung schlägt fehl, da myMockedService.getValues ​​() von meinem getesteten Code nicht aufgerufen wurde
      4. verspottet oft Schnittstellen

11

siehe Testdoppel:

  • Fake : Fakes sind Objekte mit funktionierenden Implementierungen, die jedoch nicht mit denen der Produktion identisch sind. Beispiel : In-Memory-Implementierung des Datenzugriffsobjekts oder -repositorys.
  • Stub : Stub ist ein Objekt, das vordefinierte Daten enthält und diese zum Beantworten von Anrufen während Tests verwendet. Beispiel : Ein Objekt, das einige Daten aus der Datenbank abrufen muss, um auf einen Methodenaufruf zu antworten.

  • Mocks : Mocks sind Objekte, die empfangene Anrufe registrieren. In der Testzusicherung können wir bei Mocks überprüfen, ob alle erwarteten Aktionen ausgeführt wurden. Zum Beispiel : eine Funktion, die den E-Mail-Versanddienst aufruft. Für mehr überprüfen Sie dies einfach .


1
beste Antwort meiner Meinung nach
Ero Stefano

9

Eine Fälschung ist ein Oberbegriff, der verwendet werden kann, um entweder einen Stub oder ein Scheinobjekt (handgeschrieben oder auf andere Weise) zu beschreiben, da beide wie das reale Objekt aussehen.

Ob eine Fälschung ein Stub oder ein Mock ist, hängt davon ab, wie sie im aktuellen Test verwendet wird. Wenn es verwendet wird, um eine Interaktion zu überprüfen (gegen die behauptet wird), ist es ein Scheinobjekt. Ansonsten ist es ein Stummel.

Fakes sorgt dafür, dass der Test reibungslos verläuft. Dies bedeutet, dass der Leser Ihres zukünftigen Tests versteht, wie sich das gefälschte Objekt verhält, ohne seinen Quellcode lesen zu müssen (ohne von externen Ressourcen abhängig zu sein).

Was bedeutet reibungsloser Testlauf?
Beispiel im folgenden Code:

 public void Analyze(string filename)
        {
            if(filename.Length<8)
            {
                try
                {
                    errorService.LogError("long file entered named:" + filename);
                }
                catch (Exception e)
                {
                    mailService.SendEMail("admin@hotmail.com", "ErrorOnWebService", "someerror");
                }
            }
        }

Sie möchten die mailService.SendEMail () -Methode testen. Dazu müssen Sie eine Ausnahme in Ihrer Testmethode simulieren. Sie müssen also nur eine Fake Stub-errorService-Klasse erstellen, um dieses Ergebnis zu simulieren. Dann kann Ihr Testcode testen mailService.SendEMail () -Methode. Wie Sie sehen, müssen Sie ein Ergebnis simulieren, das aus einer anderen External Dependency ErrorService-Klasse stammt.


8

Direkt aus dem Papier Mock Roles, nicht Objects , von den Entwicklern von jMock:

Stubs sind Dummy-Implementierungen von Produktionscode, die vordefinierte Ergebnisse zurückgeben. Scheinobjekte fungieren als Stubs, enthalten jedoch auch Behauptungen, um die Interaktionen des Zielobjekts mit seinen Nachbarn zu instrumentieren.

Die Hauptunterschiede sind also:

  • Erwartungen an Stubs sind normalerweise generisch, während Erwartungen an Mocks "klüger" sein können (z. B. beim ersten Aufruf, beim zweiten usw.).
  • Stubs werden hauptsächlich zum Einrichten indirekter Eingänge des SUT verwendet , während Mocks zum Testen sowohl indirekter Eingänge als auch indirekter Ausgänge des SUT verwendet werden können.

Um es zusammenzufassen, während auch die Verwirrung zu zerstreuen versucht Fowler Artikel Titel: Mocks sind Stubs, aber sie sind nicht nur Stubs .


1
Ich denke, Sie haben Recht, aber aus diesem Grund ist der Fowler-Artikel verwirrend. Der Titel des Artikels lautet "Mocks Aren't Stubs" ... aber sie SIND?! ¯_ (ツ) _ / ¯
stonedauwg

@stonedauwg, in der Tat, ich habe meinen Beitrag bearbeitet, um Ihr Wortspiel und eine Klarstellung aufzunehmen. Hoffe das hilft ein bisschen mehr.
Dimos

@stonedauwg, ein Mock ist kein Stummel, ähnlich wie ein Rechteck kein Quadrat ist. :)
Seanriordan08

7

Ich las The Art of Unit Testing und stieß auf die folgende Definition:

Eine Fälschung ist ein Oberbegriff, der verwendet werden kann, um entweder einen Stub oder ein Scheinobjekt (handgeschrieben oder auf andere Weise) zu beschreiben, da beide wie das reale Objekt aussehen. Ob eine Fälschung ein Stub oder ein Mock ist, hängt davon ab, wie sie im aktuellen Test verwendet wird. Wenn es verwendet wird, um eine Interaktion zu überprüfen (gegen die behauptet wird), ist es ein Scheinobjekt . Ansonsten ist es ein Stummel .


5

Ich bin auf diesen interessanten Artikel von UncleBob The Little Mocker gestoßen . Es erklärt die gesamte Terminologie auf sehr leicht verständliche Weise und ist daher für Anfänger nützlich. Der Artikel von Martin Fowlers ist besonders für Anfänger wie mich schwer zu lesen.


4

Stub hilft uns, den Test durchzuführen. Wie? Es gibt Werte an, die beim Ausführen des Tests helfen. Diese Werte sind selbst nicht real und wir haben diese Werte nur zum Ausführen des Tests erstellt. Zum Beispiel erstellen wir eine HashMap, um uns Werte zu geben, die den Werten in der Datenbanktabelle ähnlich sind. Anstatt direkt mit der Datenbank zu interagieren, interagieren wir mit Hashmap.

Mock ist ein gefälschtes Objekt, das den Test ausführt. wo wir behaupten.


"Anstatt direkt mit der Datenbank zu interagieren, interagieren wir mit Hashmap." ... weil wir noch keine Zeit hatten, das Datenbankmodul zu codieren, und wir den Testcode nicht ausführen konnten, ohne den Stub zu verwenden. Sonst wäre die gleiche Hasmap ein Mock! Recht?
Boris Däppen

4

Siehe das folgende Beispiel für Mocks vs Stubs mit C # und Moq Framework. Moq hat kein spezielles Schlüsselwort für Stub, aber Sie können das Mock-Objekt auch zum Erstellen von Stubs verwenden.

namespace UnitTestProject2
{
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using Moq;
    [TestClass]
    public class UnitTest1
    {
        /// <summary>
        /// Test using Mock to Verify that GetNameWithPrefix method calls Repository GetName method "once" when Id is greater than Zero
        /// </summary>
        [TestMethod]
        public void GetNameWithPrefix_IdIsTwelve_GetNameCalledOnce()
        {
            // Arrange 
            var mockEntityRepository = new Mock<IEntityRepository>();
            mockEntityRepository.Setup(m => m.GetName(It.IsAny<int>()));

            var entity = new EntityClass(mockEntityRepository.Object);
            // Act 
            var name = entity.GetNameWithPrefix(12);
            // Assert
            mockEntityRepository.Verify(m => m.GetName(It.IsAny<int>()), Times.Once);
        }
        /// <summary>
        /// Test using Mock to Verify that GetNameWithPrefix method doesn't call Repository GetName method when Id is Zero
        /// </summary>
        [TestMethod]
        public void GetNameWithPrefix_IdIsZero_GetNameNeverCalled()
        {
            // Arrange 
            var mockEntityRepository = new Mock<IEntityRepository>();
            mockEntityRepository.Setup(m => m.GetName(It.IsAny<int>()));
            var entity = new EntityClass(mockEntityRepository.Object);
            // Act 
            var name = entity.GetNameWithPrefix(0);
            // Assert
            mockEntityRepository.Verify(m => m.GetName(It.IsAny<int>()), Times.Never);
        }
        /// <summary>
        /// Test using Stub to Verify that GetNameWithPrefix method returns Name with a Prefix
        /// </summary>
        [TestMethod]
        public void GetNameWithPrefix_IdIsTwelve_ReturnsNameWithPrefix()
        {
            // Arrange 
            var stubEntityRepository = new Mock<IEntityRepository>();
            stubEntityRepository.Setup(m => m.GetName(It.IsAny<int>()))
                .Returns("Stub");
            const string EXPECTED_NAME_WITH_PREFIX = "Mr. Stub";
            var entity = new EntityClass(stubEntityRepository.Object);
            // Act 
            var name = entity.GetNameWithPrefix(12);
            // Assert
            Assert.AreEqual(EXPECTED_NAME_WITH_PREFIX, name);
        }
    }
    public class EntityClass
    {
        private IEntityRepository _entityRepository;
        public EntityClass(IEntityRepository entityRepository)
        {
            this._entityRepository = entityRepository;
        }
        public string Name { get; set; }
        public string GetNameWithPrefix(int id)
        {
            string name = string.Empty;
            if (id > 0)
            {
                name = this._entityRepository.GetName(id);
            }
            return "Mr. " + name;
        }
    }
    public interface IEntityRepository
    {
        string GetName(int id);
    }
    public class EntityRepository:IEntityRepository
    {
        public string GetName(int id)
        {
            // Code to connect to DB and get name based on Id
            return "NameFromDb";
        }
    }
}

4

Sichtweise von Stub- und Mock-Tests:

  • Stub ist eine Dummy-Implementierung, die vom Benutzer statisch ausgeführt wird, dh wenn Stub den Implementierungscode schreibt. Daher kann die Dienstdefinition und der dynamische Zustand nicht verarbeitet werden. Normalerweise erfolgt dies im JUnit-Framework, ohne das Mocking-Framework zu verwenden.

  • Mock ist auch eine Dummy-Implementierung, aber die Implementierung erfolgt dynamisch mithilfe von Mocking-Frameworks wie Mockito. So können wir Bedingungs- und Dienstdefinitionen dynamisch behandeln, dh Mocks können zur Laufzeit dynamisch aus Code erstellt werden. Mit Mock können wir Stubs also dynamisch implementieren.


3

Plus nützliche Antworten, einer der mächtigsten Punkte bei der Verwendung von Mocks als Subs

Wenn der Mitarbeiter [von dem der Hauptcode abhängt] nicht unter unserer Kontrolle steht (z. B. aus einer Bibliothek eines Drittanbieters),
ist Stub in diesem Fall schwieriger zu schreiben als zu verspotten .


2

Ich habe in meiner Antwort Python-Beispiele verwendet, um die Unterschiede zu veranschaulichen.

Stub - Stubbing ist eine Softwareentwicklungstechnik, mit der Klassenmethoden früh im Entwicklungslebenszyklus implementiert werden. Sie werden üblicherweise als Platzhalter für die Implementierung einer bekannten Schnittstelle verwendet, wobei die Schnittstelle finalisiert oder bekannt ist, die Implementierung jedoch noch nicht bekannt oder finalisiert ist. Sie beginnen mit Stubs, was einfach bedeutet, dass Sie nur die Definition einer Funktion aufschreiben und den eigentlichen Code für später belassen. Der Vorteil ist, dass Sie Methoden nicht vergessen und weiterhin über Ihr Design nachdenken können, während Sie es im Code sehen. Sie können Ihren Stub auch eine statische Antwort zurückgeben lassen, damit die Antwort sofort von anderen Teilen Ihres Codes verwendet werden kann. Stub-Objekte liefern eine gültige Antwort, aber sie sind statisch, unabhängig davon, welche Eingabe Sie übergeben. Sie erhalten immer dieselbe Antwort:

class Foo(object):
    def bar1(self):
        pass

    def bar2(self):
        #or ...
        raise NotImplementedError

    def bar3(self):
        #or return dummy data
        return "Dummy Data"

Spotten werden in Scheintestfällen verwendet, die bestätigen, dass bestimmte Methoden für diese Objekte aufgerufen werden. Scheinobjekte sind simulierte Objekte, die das Verhalten realer Objekte auf kontrollierte Weise nachahmen. Normalerweise erstellen Sie ein Scheinobjekt, um das Verhalten eines anderen Objekts zu testen. Mit Mocks können wir Ressourcen simulieren, die entweder nicht verfügbar oder für Unit-Tests zu unhandlich sind.

mymodule.py:

import os
import os.path

def rm(filename):
    if os.path.isfile(filename):
        os.remove(filename)

test.py:

from mymodule import rm
import mock
import unittest

class RmTestCase(unittest.TestCase):
    @mock.patch('mymodule.os')
    def test_rm(self, mock_os):
        rm("any path")
        # test that rm called os.remove with the right parameters
        mock_os.remove.assert_called_with("any path")

if __name__ == '__main__':
    unittest.main()

Dies ist ein sehr einfaches Beispiel, das nur rm ausführt und den Parameter bestätigt, mit dem es aufgerufen wurde. Sie können Mock für Objekte verwenden, nicht nur für die hier gezeigten Funktionen, sondern Sie können auch einen Wert zurückgeben, damit ein Mock-Objekt verwendet werden kann, um einen Stub zum Testen zu ersetzen.

Weitere Informationen zu unittest.mock finden Sie in Python 2.x. Mock ist nicht in unittest enthalten, sondern ein herunterladbares Modul, das über pip heruntergeladen werden kann (pip install mock).

Ich habe auch "The Art of Unit Testing" von Roy Osherove gelesen und ich denke, es wäre großartig, wenn ein ähnliches Buch mit Python- und Python-Beispielen geschrieben würde. Wenn jemand von einem solchen Buch weiß, teilen Sie es bitte. Prost :)


2

Ein Stub ist ein gefälschtes Objekt, das zu Testzwecken erstellt wurde. Ein Mock ist ein Stub, der aufzeichnet, ob erwartete Anrufe tatsächlich aufgetreten sind.


2

Ein Stub ist eine leere Funktion, mit der unbehandelte Ausnahmen bei Tests vermieden werden:

function foo(){}

Ein Mock ist eine künstliche Funktion, mit der Betriebssystem-, Umgebungs- oder Hardwareabhängigkeiten während der Tests vermieden werden:

function foo(bar){ window = this; return window.toString(bar); }

In Bezug auf Behauptungen und Zustand:

  • Mocks werden vor einem Ereignis oder einer Statusänderung aktiviert
  • Stubs werden nicht aktiviert, sondern geben den Status vor einem Ereignis an, um zu vermeiden, dass Code von nicht verwandten Einheiten ausgeführt wird
  • Spione werden wie Stubs eingerichtet und nach einem Ereignis oder einer Statusänderung bestätigt
  • Fälschungen werden nicht bestätigt, sondern nach einem Ereignis mit fest codierten Abhängigkeiten ausgeführt, um einen Status zu vermeiden

Verweise


2
+1 zum Hinzufügen von Spionen zum Glossar. Ich denke auch, Sie meinen "Spione sind wie Verspottungen eingerichtet", nicht "Spione sind wie Stummel eingerichtet"
Sameh Deabes


2

Ein Mock ist sowohl ein technisches als auch ein funktionales Objekt.

Der Schein ist technisch . Es wird in der Tat von einer Spottbibliothek erstellt (EasyMock, JMockit und in jüngerer Zeit sind Mockito dafür bekannt), dank der Bytecode-Generierung .
Die Scheinimplementierung wird so generiert , dass wir sie instrumentieren können, um beim Aufrufen einer Methode einen bestimmten Wert zurückzugeben, aber auch einige andere Dinge wie die Überprüfung, ob eine Scheinmethode mit bestimmten Parametern aufgerufen wurde (strenge Prüfung) oder welche Parameter auch immer ( keine strenge Kontrolle).

Ein Mock instanziieren:

@Mock Foo fooMock

Verhalten aufzeichnen:

when(fooMock.hello()).thenReturn("hello you!");

Aufruf überprüfen:

verify(fooMock).hello()

Dies ist eindeutig nicht die natürliche Methode, um die Foo-Klasse / das Foo-Verhalten zu instanziieren / zu überschreiben. Deshalb beziehe ich mich auf einen technischen Aspekt.

Aber das Mock ist auch funktional , weil es eine Instanz der Klasse ist , müssen wir von der SUT zu isolieren. Und mit aufgezeichneten Verhaltensweisen könnten wir es im SUT genauso verwenden wie mit einem Stub.


Der Stub ist nur ein funktionales 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 Verhaltens-Fixtures, die während unserer Unit-Tests benötigt werden, explizit definiert werden müssen.
Zum Beispiel hello()müsste ein Stub die FooKlasse in eine Unterklasse unterteilen (oder ihre Schnittstelle implementieren, über die sie verfügt) und Folgendes überschreiben hello() :

public class HelloStub extends Hello{    
  public String hello { 
      return "hello you!"; 
  }
}

Wenn für ein anderes Testszenario eine andere Wertrückgabe erforderlich ist, müssen wir wahrscheinlich eine generische Methode zum Festlegen der Rückgabe definieren:

public class HelloStub extends Hello{    
  public HelloStub(String helloReturn){
       this.helloReturn = helloReturn;
  }
  public String hello { 
      return helloReturn; 
  }
}

Anderes Szenario: Wenn ich eine Nebenwirkungsmethode hätte (keine Rückgabe) und überprüfen würde, ob diese Methode aufgerufen wurde, hätte ich wahrscheinlich einen Booleschen Wert oder einen Zähler in die Stub-Klasse einfügen müssen, um zu zählen, wie oft die Methode aufgerufen wurde.


Fazit

Der Stub benötigt oft viel Overhead / Code, um für Ihren Unit-Test zu schreiben. Was Mock verhindert, dank der sofort einsatzbereiten Aufnahme- / Überprüfungsfunktionen.
Aus diesem Grund wird der Stub-Ansatz heutzutage in der Praxis mit dem Aufkommen hervorragender Scheinbibliotheken selten verwendet.


Über den Artikel von Martin Fowler: Ich denke nicht, dass ich ein "Mockist" -Programmierer bin, während ich Mocks benutze und Stubs vermeide.
Aber ich verwende Mock, wenn es wirklich erforderlich ist (ärgerliche Abhängigkeiten), und ich bevorzuge Test-Slicing- und Mini-Integrationstests, wenn ich eine Klasse mit Abhängigkeiten teste, deren Mocking ein Overhead wäre.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.