Was ist Spott?


Antworten:


598

Prolog: Wenn Sie das Substantiv nachschlagen Mock im Wörterbuch werden Sie feststellen , dass eine der Definitionen des Wortes ist etwas als Nachahmung gemacht .


Das Verspotten wird hauptsächlich beim Testen von Einheiten verwendet. Ein zu testendes Objekt kann Abhängigkeiten von anderen (komplexen) Objekten aufweisen. Um das Verhalten des Objekts zu isolieren, möchten Sie die anderen Objekte durch Mocks ersetzen, die das Verhalten der realen Objekte simulieren. Dies ist nützlich, wenn es unpraktisch ist, die realen Objekte in den Komponententest einzubeziehen.

Kurz gesagt, beim Verspotten werden Objekte erstellt, die das Verhalten realer Objekte simulieren.


Manchmal möchten Sie vielleicht zwischen Verspotten und Stubben unterscheiden . Es mag einige Meinungsverschiedenheiten über dieses Thema geben, aber meine Definition eines Stubs ist ein "minimales" simuliertes Objekt. Der Stub implementiert gerade genug Verhalten, damit das zu testende Objekt den Test ausführen kann.

Ein Mock ist wie ein Stub, aber der Test überprüft auch, ob das zu testende Objekt den Mock wie erwartet aufruft. Ein Teil des Tests besteht darin, zu überprüfen, ob das Modell korrekt verwendet wurde.

Ein Beispiel: Sie können eine Datenbank stubben, indem Sie eine einfache In-Memory-Struktur zum Speichern von Datensätzen implementieren. Das zu testende Objekt kann dann Datensätze lesen und in den Datenbankstub schreiben, damit dieser den Test ausführen kann. Dies könnte ein Verhalten des Objekts testen, das nicht mit der Datenbank zusammenhängt, und der Datenbankstub würde nur enthalten sein, damit der Test ausgeführt werden kann.

Wenn Sie stattdessen überprüfen möchten, ob das zu testende Objekt bestimmte Daten in die Datenbank schreibt, müssen Sie die Datenbank verspotten. Ihr Test würde dann Aussagen darüber enthalten, was in den Datenbank-Mock geschrieben wurde.


18
Dies ist eine gute Antwort, schränkt jedoch das Konzept der Verspottung von Objekten unnötig ein . Das Ersetzen von "Objekt" durch "Einheit" würde es allgemeiner machen.
Rogério

1
Ich verstehe den Unterschied zwischen Stub und Mock. Die einzige Sache ist, dass Sie, wenn Sie Ihre Fälle mit einem Stub testen und dieser erfolgreich ist, nicht zu dem Schluss kommen können, dass Sie den Stub bereits verwenden, sodass Sie die Überprüfung nicht mehr benötigen ?
Honig

91

Andere Antworten erklären, was Spott ist. Lassen Sie sich mit verschiedenen Beispielen durch die Sache führen . Und glauben Sie mir, es ist tatsächlich viel einfacher als Sie denken.

tl; dr Es ist eine Instanz der ursprünglichen Klasse. Es hat andere Daten in injiziert , so vermeiden Sie die injizierten Teile zu testen und nur konzentrieren auf die Prüfung der Details der Implementierung Ihrer Klasse / Funktionen.

Ein einfaches Beispiel:

class Foo {
    func add (num1: Int, num2: Int) -> Int { // Line A 
        return num1 + num2 // Line B
    }
}

let unit = Foo() // unit under test
assertEqual(unit.add(1,5),6)

Wie Sie sehen können, teste ich LineA nicht, dh ich validiere die Eingabeparameter nicht. Ich überprüfe nicht, ob num1, num2 eine Ganzzahl sind. Ich habe keine Behauptungen dagegen.

Ich teste nur, ob LineB (meine Implementierung ) die verspotteten Werte gegeben hat 1und 5tut, was ich erwarte.

Offensichtlich kann dies im eigentlichen Wort viel komplexer werden. Die Parameter können ein benutzerdefiniertes Objekt wie eine Person, eine Adresse sein oder die Implementierungsdetails können mehr als ein einzelnes sein +. Aber die Logik des Testens wäre dieselbe.

Nicht codierendes Beispiel:

Angenommen, Sie bauen eine Maschine, die den Typ und den Markennamen elektronischer Geräte für eine Flughafensicherheit identifiziert. Die Maschine verarbeitet dazu, was sie mit ihrer Kamera sieht.

Jetzt kommt Ihr Manager zur Tür herein und bittet Sie, sie einem Unit-Test zu unterziehen.

Dann können Sie als Entwickler entweder 1000 echte Objekte wie ein MacBook Pro, Google Nexus, eine Banane, ein iPad usw. vor sich bringen und testen, ob alles funktioniert.

Sie können aber auch verspottete Objekte verwenden, z. B. ein identisch aussehendes MacBook Pro (ohne echte Innenteile) oder eine Plastikbanane davor. Sie können sich sparen, wenn Sie in 1000 echte Laptops und verrottende Bananen investieren.

Der Punkt ist, dass Sie nicht versuchen zu testen, ob die Banane gefälscht ist oder nicht. Noch testen, ob der Laptop gefälscht ist oder nicht. Alles, was Sie tun, ist zu testen, ob Ihr Computer, sobald er eine Banane sieht, sagen würde, not an electronic deviceund für ein MacBook Pro würde es sagen : Laptop, Apple. Für die Maschine sollte das Ergebnis ihrer Erkennung für gefälschte / verspottete Elektronik und echte Elektronik dasselbe sein

Die oben erwähnte Logik gilt auch für Unit-Tests des tatsächlichen Codes. Dies ist eine Funktion, die mit realen Werten, die Sie durch reale Eingaben (und Interaktionen) erhalten oder die verspottet werden, genauso funktionieren sollteWerte, die Sie während des Unit-Tests injizieren. Und genau wie Sie sich vor der Verwendung einer echten Banane oder eines echten MacBook schützen, ersparen Sie sich mit Unit-Tests (und Verspottungen), dass Sie etwas tun müssen, das Ihren Server veranlasst, einen Statuscode von 500, 403, 200 usw. zurückzugeben (Forcen) Ihr Server löst nur dann 500 aus, wenn der Server ausgefallen ist, während 200 ausgefallen ist. Es wird schwierig, 100 netzwerkorientierte Tests durchzuführen, wenn Sie zwischen dem Hoch- und Herunterschalten des Servers ständig 10 Sekunden warten müssen. Stattdessen injizieren / verspotten Sie eine Antwort mit dem Statuscode 500, 200, 403 usw. und testen Ihre Einheit / Funktion mit einem injizierten / verspotteten Wert.

Codierungsbeispiel:

Angenommen, Sie schreiben eine iOS-Anwendung und haben Netzwerkanrufe. Ihre Aufgabe ist es, Ihre Anwendung zu testen . Zu testen / zu identifizieren, ob die Netzwerkanrufe wie erwartet funktionieren oder nicht, ist NICHT IHRE VERANTWORTUNG. Es liegt in der Verantwortung einer anderen Partei (Serverteam), dies zu testen. Sie müssen diese (Netzwerk-) Abhängigkeit entfernen und dennoch weiterhin Ihren gesamten Code testen, der um sie herum funktioniert .

Ein Netzwerkanruf kann verschiedene Statuscodes 404, 500, 200, 303 usw. mit einer JSON-Antwort zurückgeben.

Es wird davon ausgegangen, dass Ihre App für alle funktioniert (im Fehlerfall sollte Ihre App den erwarteten Fehler auslösen). Was Sie mit dem Verspotten tun, ist, dass Sie "imaginär - ähnlich wie echte" Netzwerkantworten (wie ein 200-Code mit einer JSON-Datei) erstellen und Ihren Code testen, ohne "den realen Netzwerkanruf zu tätigen und auf Ihre Netzwerkantwort zu warten". Sie können die Netzwerkantwort für ALLE Arten von Netzwerkantworten manuell fest codieren / zurückgeben und prüfen, ob Ihre App wie erwartet funktioniert. (Sie nehmen niemals eine 200 mit falschen Daten an / testen sie, da dies nicht in Ihrer Verantwortung liegt. Sie sind dafür verantwortlich, Ihre App mit einer korrekten 200 zu testen. Bei einer 400, 500 testen Sie, ob Ihre App den richtigen Fehler auslöst.)

Dieses Schaffen von Imaginärem - ähnlich wie Real - wird als Verspotten bezeichnet.

Zu diesem Zweck können Sie Ihren Originalcode nicht verwenden (Ihr Originalcode enthält nicht die vorab eingefügten Antworten, oder?). Sie müssen etwas hinzufügen, die normalerweise nicht benötigten Dummy-Daten (oder einen Teil Ihrer Klasse) einfügen / einfügen.

Sie erstellen also eine Instanz der ursprünglichen Klasse und fügen alles hinzu, was Sie benötigen (hier ist die Netzwerk-HTTP-Antwort, Daten ODER im Fehlerfall übergeben Sie den richtigen errorString, HTTPResponse), und testen dann die verspottete Klasse.

Kurz gesagt, Spott bedeutet, das , was Sie testen , zu vereinfachen und einzuschränken und Sie dazu zu bringen, zu füttern, wovon eine Klasse abhängt. In diesem Beispiel können Sie vermeiden , testen das Netzwerk nennt sich , und stattdessen Test , ob Ihre App funktioniert wie erwartet mit den injizierten Ausgänge / Antworten - durch spöttische Klassen

Natürlich testen Sie jede Netzwerkantwort separat.


Eine Frage, die ich immer im Kopf hatte, war: Die Verträge / Endpunkte und im Grunde die JSON-Antwort meiner APIs werden ständig aktualisiert. Wie kann ich Unit-Tests schreiben, die dies berücksichtigen?

Um dies näher zu erläutern: Angenommen, das Modell benötigt einen Schlüssel / ein Feld mit dem Namen username. Sie testen dies und Ihr Test besteht. 2 Wochen später ändert das Backend den Namen des Schlüssels in id. Ihre Tests bestehen noch. Recht? oder nicht?

Ist es die Verantwortung des Backend-Entwicklers, die Mocks zu aktualisieren? Sollte es Teil unserer Vereinbarung sein, dass sie aktualisierte Verspottungen bereitstellen?

Die Antwort auf das oben genannte Problem lautet: Unit-Tests + Ihr Entwicklungsprozess als clientseitiger Entwickler sollte / würde veraltete verspottete Antworten erhalten. Wenn du mich fragst wie? Nun, die Antwort lautet:

Unsere eigentliche App würde fehlschlagen (oder nicht fehlschlagen, aber nicht das gewünschte Verhalten aufweisen), ohne aktualisierte APIs zu verwenden. Wenn dies fehlschlägt, werden wir Änderungen an unserem Entwicklungscode vornehmen. Was wiederum dazu führt, dass unsere Tests fehlschlagen ... was wir korrigieren müssen. (Wenn wir den TDD-Prozess korrekt ausführen möchten, dürfen wir keinen Code über das Feld schreiben, es sei denn, wir schreiben den Test dafür ... und sehen, dass er fehlschlägt, und schreiben dann den eigentlichen Entwicklungscode dafür.)

Dies alles bedeutet, dass das Backend nicht sagen muss: „Hey, wir haben die Mocks aktualisiert“. Dies geschieht schließlich durch Ihre Codeentwicklung / Ihr Debugging. ‌ّ Weil alles Teil des Entwicklungsprozesses ist! Wenn das Backend die verspottete Antwort für Sie liefert, ist es einfacher.

Mein ganzer Punkt dabei ist, dass (wenn Sie das Aktualisieren der verspotteten API-Antwort nicht automatisieren können) eine gewisse menschliche Interaktion erforderlich ist, dh manuelle Aktualisierungen von JSONs und kurze Besprechungen, um sicherzustellen, dass ihre Werte auf dem neuesten Stand sind, werden Teil Ihres Prozesses

Dieser Abschnitt wurde dank einer lockeren Diskussion in unserer CocoaHead-Meetup-Gruppe geschrieben


Nur für iOS-Entwickler:

Ein sehr gutes Beispiel für Spott ist dieser auf das Praktische Protokoll ausgerichtete Vortrag von Natasha Muraschev . Fahren Sie einfach mit Minute 18:30 fort, obwohl die Folien möglicherweise nicht mehr mit dem tatsächlichen Video synchronisiert sind 🤷‍♂️

Ich mag diesen Teil aus dem Transkript wirklich:

Da dies ein Test ist ... möchten wir sicherstellen, dass die getFunktion von Gettableaufgerufen wird, da sie zurückkehren kann und die Funktion theoretisch von überall aus eine Reihe von Lebensmitteln zuweisen kann . Wir müssen sicherstellen, dass es aufgerufen wird;


3
Tolles Beispiel, ich möchte nur hinzufügen, dass in diesem speziellen Beispiel die Unterklasse als Mock fungiert, aber in diesem Beispiel wird auch Stubbing verwendet. Die fest codierten JSON-Antworten werden als gestoppelte Antworten betrachtet. Ich füge dies nur hinzu, weil es schwierig sein kann, zwischen Mocks und Stubs zu unterscheiden, aber dieses Beispiel zeigt deutlich, wie beide zusammen verwendet werden können.
user3344977

Hervorragende Erklärung, danke. Eine kleine Änderung an der Frage nach der API-Änderung. Was ist, wenn es nicht Ihre API ist und Sie nicht Teil des Entwicklungsprozesses sind? Ich möchte wissen, wann meine Clientbibliothek ausfällt.
ThinkDigital

@ThinkDigital Gute API-Anbieter haben gute Versionshinweise und kommunizieren Änderungen ordnungsgemäß. Wenn Sie diesen Kanal nicht haben, ist es möglicherweise an der Zeit, an einer Besprechung teilzunehmen und darüber zu diskutieren Gute Entwickler werden sich immer mit API-Änderungen einer neuen Version befassen und vermeiden, nur die API-Version zu aktualisieren. Haben Sie API-Versionen? Wenn keiner von beiden es fängt, werden Sie es bei der Qualitätssicherung herausfinden, dann aktualisieren Sie Ihre Tests ← Pflicht des gesamten Teams. → Pflicht eines einzelnen Entwicklers: sollte nicht viel interessieren. Behandeln Sie einfach den Fall, in dem der Server einen Fehler zurückgibt oder der Server keinen Fehler zurückgibt, aber json nicht analysieren kann, oder behandeln Sie den korrekten Fall.
Honey

Vielen Dank für Ihre Antwort, @Honey! In meinem Fall verwalte ich einen Client für pub.dev , der über eine API verfügt, die jedoch stark fehlt. So sehr, dass es besser war, eine API durch Scraping ihrer Site zu erstellen, als ihre offizielle API zu verwenden. Aus diesem Grund können Änderungen an der Site den Code beschädigen, und in diesem Fall müssen sie niemanden aktualisieren. Die Site ist Open Source, aber es ist etwas anderes, eine API zu pflegen, die auf Änderungen basiert, die auf einer trivialeren Basis vorgenommen werden.
ThinkDigital

32

Es gibt viele Antworten auf SO und gute Beiträge im Internet über Spott. Ein Ort, an dem Sie vielleicht anfangen möchten, ist der Beitrag von Martin Fowler Mocks Aren't Stubs, in dem er viele Ideen zum Verspotten bespricht.

In einem Absatz - Mocking ist eine spezielle Technik, mit der eine Codeeinheit getestet werden kann, ohne auf Abhängigkeiten angewiesen zu sein. Im Allgemeinen unterscheidet sich Mocking von anderen Methoden dadurch, dass Mock-Objekte, die zum Ersetzen von Code-Abhängigkeiten verwendet werden, das Setzen von Erwartungen ermöglichen. Ein Mock-Objekt weiß, wie es von Ihrem Code aufgerufen werden soll und wie es reagiert.


Ihre ursprüngliche Frage erwähnte TypeMock, daher habe ich meine Antwort darauf unten hinterlassen:

TypeMock ist der Name eines kommerziellen Mocking-Frameworks .

Es bietet alle Funktionen der kostenlosen Mocking-Frameworks wie RhinoMocks und Moq sowie einige leistungsstärkere Optionen.

Ob Sie TypeMock benötigen oder nicht, ist höchst umstritten - Sie können mit kostenlosen Verspottungsbibliotheken die meisten Verspottungen durchführen, die Sie sich jemals wünschen würden, und viele argumentieren, dass die von TypeMock angebotenen Fähigkeiten Sie häufig von einem gut gekapselten Design abbringen.

Wie in einer anderen Antwort angegeben, ist "TypeMocking" eigentlich kein definiertes Konzept, sondern kann als die Art der Verspottung verstanden werden, die TypeMock anbietet, indem der CLR-Profiler zum Abfangen von .NET-Aufrufen zur Laufzeit verwendet wird, wodurch Objekte viel besser gefälscht werden können (keine Anforderungen) B. Schnittstellen oder virtuelle Methoden benötigen).


@ Masoud hat TypeMock nie erwähnt. Seine Frage betraf allgemein "Typenspott".
Peter Lillevold

4
@Peter - wie in einem anderen Kommentar erwähnt, überprüfen Sie den Bearbeitungsverlauf der Frage. Ich kann nicht viel tun, wenn ich eine Antwort poste und dann die ursprüngliche Frage komplett geändert wird.
David Hall

9

Mock ist eine Methode / ein Objekt, die das Verhalten einer realen Methode / eines realen Objekts auf kontrollierte Weise simuliert. Scheinobjekte werden beim Testen von Einheiten verwendet.

Oft ruft eine zu testende Methode andere externe Dienste oder darin enthaltene Methoden auf. Diese werden Abhängigkeiten genannt. Einmal verspottet, verhalten sich die Abhängigkeiten so, wie wir sie definiert haben.

Da die Abhängigkeiten durch Mocks gesteuert werden, können wir das Verhalten der von uns codierten Methode leicht testen. Dies ist Unit-Test.

Was ist der Zweck von Scheinobjekten?

Mocks vs Stubs

Unit Tests vs Funktionstests


7

Beim Verspotten werden Pseudoobjekte generiert, die das Verhalten realer Objekte für Tests simulieren


5

Der Zweck des Verspotten von Typen besteht darin, Abhängigkeiten zu trennen, um den Test auf eine bestimmte Einheit zu isolieren. Stubs sind einfache Surrogate, während Mocks Surrogate sind, die die Verwendung überprüfen können. Ein Mocking-Framework ist ein Tool, mit dem Sie Stubs und Mocks generieren können.

EDIT : Da der ursprüngliche Wortlaut "Type Mocking" erwähnt, hatte ich den Eindruck, dass dies mit TypeMock zusammenhängt. Nach meiner Erfahrung ist der allgemeine Begriff nur "spöttisch". Bitte ignorieren Sie die folgenden Informationen speziell zu TypeMock.

TypeMock Isolator unterscheidet sich von den meisten anderen Mocking-Frameworks dadurch, dass es meine modifizierende IL im laufenden Betrieb funktioniert. Dadurch können Typen und Instanzen verspottet werden, die die meisten anderen Frameworks nicht verspotten können. Um diese Typen / Instanzen mit anderen Frameworks zu verspotten, müssen Sie Ihre eigenen Abstraktionen bereitstellen und diese verspotten.

TypeMock bietet große Flexibilität auf Kosten einer sauberen Laufzeitumgebung. Als Nebeneffekt der Art und Weise, wie TypeMock seine Ergebnisse erzielt, erhalten Sie manchmal sehr seltsame Ergebnisse, wenn Sie TypeMock verwenden.


@ Masoud hat TypeMock nie erwähnt. Seine Frage betraf allgemein "Typenspott".
Peter Lillevold

1
@Peter: Der ursprüngliche Wortlaut war "Was ist Typenspott?".
Brian Rasmussen

Ich kenne. Da "Type Mocking" nicht gleichbedeutend mit "TypeMock" ist, finde ich sowohl Ihre als auch die Antwort von @Oded ziemlich falsch.
Peter Lillevold

1
@Peter: Nach meiner Erfahrung ist der allgemeine Begriff "spöttisch", aber auf jeden Fall habe ich meine Antwort aktualisiert, um dies hoffentlich klar zu machen. Danke für die Eingabe.
Brian Rasmussen

3

Ich würde denken, dass die Verwendung des TypeMock-Isolator-Mocking-Frameworks TypeMocking wäre.

Es ist ein Tool, das Mocks für Unit-Tests generiert, ohne dass Sie Ihren Code unter Berücksichtigung von IoC schreiben müssen.


@ Masoud hat TypeMock nie erwähnt. Seine Frage betraf allgemein "Typenspott".
Peter Lillevold

3
Eigentlich enthielt die ursprüngliche Frage das Wort "Typ" vor "Verspotten", wurde aber später herausgeschnitten. Aus diesem Grund enthalten einige der Antworten spezifische Informationen zu TypeMock.
Martin Liversage

1

Wenn es sich bei Ihrem Mock um eine Netzwerkanforderung handelt, besteht eine andere Alternative darin, einen echten Testserver zu verwenden. Mit diesem Dienst können Sie eine Anfrage und Antwort für Ihre Tests generieren. http://testerurl.com/


Ich habe gerade versucht, darauf zuzugreifen, und es dauerte einige Minuten. Wer soll sagen, dass Anfragen nicht auch heimlich protokolliert werden? Schließlich könnte dies als Kommentar besser dran sein :)
Kieren Johnstone

Ich habe es tatsächlich heruntergenommen, da ich keine Lust hatte, es auf ein kostenloses Hosting zu verschieben. Ja, das hätte ein Kommentar sein sollen. Es ist Open Source. Wenn Sie also Bedenken hinsichtlich der Protokollierung von Anforderungen haben, können Sie Ihre eigenen ausführen. github.com/captainchung/TesterUrl
Matthew Chung
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.