Was ist Spott? .
Was ist Spott? .
Antworten:
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.
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 1
und 5
tut, 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.
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 device
und 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.
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
get
Funktion vonGettable
aufgerufen 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;
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).
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.
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.
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.
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/