web-dev-qa-db-de.com

Was ist der Unterschied zwischen Fake, Spott und Stubbing?

Ich weiß, wie ich diese Ausdrücke verwende, aber ich frage mich, ob es Definitionen für Fake, Spott und Stubbing für Unit-Tests gibt. Wie definieren Sie diese für Ihre Tests? Beschreiben Sie Situationen, in denen Sie sie jeweils verwenden könnten.

So verwende 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 gibt, die Werte dynamisch festzulegen, um zurückzukehren,/Ausnahmen, die von bestimmten Methoden geworfen werden, und die Möglichkeit bietet, zu überprüfen, ob bestimmte Methoden aufgerufen/nicht aufgerufen wurden.

Stub : Wie eine Scheinklasse, mit der Ausnahme, dass sie nicht die Möglichkeit bietet, zu überprüfen, ob Methoden aufgerufen wurden/nicht aufgerufen wurden.

Mocks und Stubs können von Hand oder von einem Mocking Framework erzeugt werden. Gefälschte Klassen werden von Hand erzeugt. Ich verwende Mocks hauptsächlich, um die Interaktionen zwischen meiner Klasse und abhängigen Klassen zu überprüfen. Ich verwende Stubs, wenn ich die Interaktionen überprüft habe und alternative Pfade durch meinen Code teste. Ich benutze gefälschte Klassen in erster Linie, um Datenabhängigkeiten auszugrenzen oder wenn Mocks/Stubs zu langwierig sind, um sie jedes Mal neu einzurichten.

563
tvanfosson

Sie können einige Informationen erhalten:

Von Martin Fowler über Mock und Stub

Fake -Objekte verfügen zwar über funktionierende Implementierungen, nehmen jedoch normalerweise eine Abkürzung, wodurch sie nicht für die Produktion geeignet sind

Stubs bieten Antworten auf Anrufe, die während des Tests gemacht wurden, und antworten in der Regel nicht auf alles, was sich außerhalb des für den Test vorgesehenen Programms befindet. Stubs können auch Informationen zu Anrufen aufzeichnen, z. B. einen E-Mail-Gateway-Stub, der die von ihm gesendeten Nachrichten speichert, oder nur, wie viele Nachrichten er gesendet hat.

Mocks sind das, worüber wir hier sprechen: Objekte, die mit Erwartungen vorprogrammiert sind und eine Spezifikation der Anrufe enthalten, die sie erwarten sollen.

Von xunitpattern :

Fake: Wir erwerben oder bauen eine sehr einfache Implementierung derselben Funktionalität, die von einer Komponente bereitgestellt wird, von der das SUT abhängt, und weist das SUT an, diese anstelle des Real 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 verwenden. Ein Schlüsselindikator für die Verwendung eines Test-Stubs ist der nicht getestete Code, da die indirekten Eingaben des SUT nicht gesteuert werden können

Mock Object, das dieselbe Schnittstelle wie ein Objekt implementiert, von dem das SUT (System Under Test) abhängt. Wir können ein Scheinobjekt als Beobachtungspunkt verwenden, wenn wir eine Verhaltensüberprüfung durchführen müssen, um zu vermeiden, dass eine Anforderung nicht getestet wird (siehe Produktionsfehler auf Seite X), die durch die Unmöglichkeit verursacht werden, Nebenwirkungen beim Aufrufen von Methoden auf dem SUT zu beobachten.

Persönlich

Ich versuche zu vereinfachen mit: Mock und Stub. Ich verwende Mock, wenn es ein Objekt ist, das einen Wert zurückgibt, der auf die getestete Klasse festgelegt ist. Ich benutze Stub, um eine zu testende Interface- oder Abstract-Klasse nachzuahmen. In der Tat spielt es keine Rolle, wie Sie es nennen, es handelt sich dabei um Klassen, die nicht in der Produktion verwendet werden, und sie werden als Hilfsklassen zum Testen verwendet.

452

Stub - ein Objekt, das vordefinierte Antworten für Methodenaufrufe liefert. 

Mock - ein Objekt, an das Sie Erwartungen stellen.

Fake - ein Objekt mit eingeschränkten Fähigkeiten (zum Testen), z. ein gefälschter Webservice. 

Test Double ist der Oberbegriff für Stubs, Mocks und Fakes. Aber informell hört man oft, dass die Leute sie einfach als Scherze bezeichnen. 

171
Mike

Ich bin überrascht, dass es diese Frage schon so lange gibt und bis jetzt noch niemand eine Antwort auf der Grundlage von Roy Osheroves "The Art of Unit Testing" gegeben hat.

Definiert in "3.1 Stubs einführen" einen Stub als:

Ein Stub ist ein steuerbarer Ersatz für eine bestehende Abhängigkeit (oder Mitarbeiter) im System. Mit einem Stub können Sie Ihren Code ohne .__ testen. direkt mit der Abhängigkeit umgehen.

Und definiert den Unterschied zwischen Stubs und Mocks als:

Die Hauptsache, die Sie bei Mocks im Vergleich zu Stubs beachten sollten, ist, dass Mocks wie Stubs aussehen, Sie dagegen gegen das Mock-Objekt vorgehen, während Sie sich nicht gegen einen Stub behaupten.

Fake ist nur der Name für Stubs und Mocks. Zum Beispiel, wenn Sie sich nicht für die Unterscheidung zwischen Stubs und Mock interessieren.

Die Art, wie Osherove zwischen Stubs und Mock unterscheidet, bedeutet, dass jede Klasse, die als Fälschung für Tests verwendet wird, sowohl ein Stub als auch ein Mock sein kann. Was es für einen bestimmten Test ist, hängt vollständig davon ab, wie Sie die Prüfungen in Ihrem Test schreiben. 

  • Wenn Ihr Test Werte in der zu testenden Klasse oder tatsächlich an einem anderen Ort als der Fälschung überprüft, wurde die Fälschung als Stub verwendet. Es hat lediglich Werte für die zu testende Klasse bereitgestellt, entweder direkt durch Werte, die von Aufrufen zurückgegeben werden, oder indirekt durch das Hervorrufen von Nebenwirkungen (in einem bestimmten Zustand) als Folge von Aufrufen.
  • Wenn Ihr Test die Werte der Fälschung überprüft, wurde er als Schein verwendet.

Beispiel für einen Test, bei dem die Klasse FakeX als Stub verwendet wird:

const pleaseReturn5 = 5;
var fake = new FakeX(pleaseReturn5);
var cut = new ClassUnderTest(fake);

cut.SquareIt;

Assert.AreEqual(25, cut.SomeProperty);

Die fake-Instanz wird als Stub verwendet, da die Assert keine fake verwendet.

Beispiel für einen Test, bei dem Testklasse X als Mock verwendet wird:

const pleaseReturn5 = 5;
var fake = new FakeX(pleaseReturn5);
var cut = new ClassUnderTest(fake);

cut.SquareIt;

Assert.AreEqual(25, fake.SomeProperty);

In diesem Fall prüft Assert einen Wert in fake, wodurch ein Schein simuliert wird.

Nun, diese Beispiele sind natürlich sehr durchdacht, aber ich sehe in dieser Unterscheidung große Verdienste. Es macht Sie bewusst, wie Sie Ihre Sachen testen und wo die Abhängigkeiten Ihres Tests liegen.

Ich stimme dem von Osherove zu

aus reiner wartungsfähigkeit betrachtet, verursacht die verwendung von stößen in meinen tests mehr problem, als sie nicht zu verwenden. Das war meine Erfahrung, aber ich lerne immer etwas Neues.

Gegen die Fälschung vorzugehen ist etwas, das Sie wirklich vermeiden möchten, da Ihre Tests dadurch stark von der Implementierung einer Klasse abhängen, die überhaupt nicht die getestete ist. Dies bedeutet, dass die Tests für die Klasse ActualClassUnderTest anfangen können zu brechen, da sich die Implementierung für ClassUsedAsMock geändert hat. Und das riecht mir übel. Tests für ActualClassUnderTest sollten vorzugsweise nur dann abbrechen, wenn ActualClassUnderTest geändert wird.

Mir ist klar, dass das Schreiben von Behauptungen gegen die Fälschung eine übliche Praxis ist, insbesondere wenn Sie ein Spott-Typ von TDD-Abonnenten sind. Ich glaube, ich bin fest mit Martin Fowler im klassizistischen Lager (siehe Martin Fowlers "Mocks are Stubs" ) und vermeide wie Osherove Interaktionstests (was nur durch die Behauptung gegen die Fälschung möglich ist) so weit wie möglich .

Für Spaß beim Lesen darüber, warum Sie die hier definierten Stöße vermeiden sollten, suchen Sie nach "Fowler Mockist Classicist". Sie finden eine Fülle von Meinungen.

78
Marjan Venema

Wie in der Antwort mit den meisten Stimmen erwähnt, erörtert Martin Fowler diese Unterscheidungen in Mocks Are Don't Stubs und insbesondere in der Unterüberschrift The Difference Between Mocks and Stubs um diesen Artikel zu lesen.

Anstatt sich auf wie zu konzentrieren, sind diese Dinge anders, ich denke, es ist aufschlussreicher, sich auf warum zu konzentrieren, das sind unterschiedliche Konzepte. Jedes existiert für einen anderen Zweck.

Fälschungen

Eine Fälschung ist eine Implementierung, die sich "natürlich" verhält, aber nicht "real" ist. Dies sind unscharfe Konzepte, und so haben unterschiedliche Menschen unterschiedliche Auffassungen darüber, was die Dinge zu einer Fälschung macht.

Ein Beispiel für eine Fälschung ist eine speicherinterne Datenbank (z. B. die Verwendung von sqlite mit :memory: Geschäft). Sie würden dies niemals für die Produktion verwenden (da die Daten nicht persistent sind), 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 einen 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 zum Speichern auf der Festplatte eine Fälschung. (Oder Sie könnten sogar die Operation "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, aber immer einen Cache-Miss zurückgibt, wäre eine Art Fake.

Der Zweck einer Fälschung ist nicht, um das Verhalten des zu testenden Systems zu beeinflussen , sondern um zu vereinfachen die Implementierung des Tests (durch Entfernen unnötiger oder schwerer Abhängigkeiten).

Stubs

Ein Stub ist eine Implementierung, die sich "unnatürlich" verhält. Es ist vorkonfiguriert (normalerweise von der Testeinrichtung), um auf bestimmte Eingänge mit bestimmten Ausgängen 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 einen Code schreiben, der mit interagiert a REST API, Sie könnten stub out ​​die REST API mit einer API, die immer eine vorgefertigte Antwort zurückgibt oder auf die reagiert 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, beispielsweise die Antwort Ihrer Benutzer, 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 anweisen. 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, aber mit Überprüfung hinzugefügt. Der Zweck Ein Schein ist, Aussagen darüber zu machen, wie Ihr zu testendes System mit der Abhängigkeit interagiert hat .

Wenn Sie beispielsweise einen Test für ein System schreiben, das Dateien auf eine Website hochlädt, können Sie ein mock erstellen, das eine Datei akzeptiert und mit dem Sie bestätigen können, dass die hochgeladene Datei korrekt ist. Oder in kleinerem Maßstab wird häufig ein Mock eines Objekts verwendet, um zu überprüfen, ob das zu testende System bestimmte Methoden des gespielten Objekts aufruft.

Mocks sind an Interaktionstests gebunden, eine spezielle Testmethode. Leute, die es vorziehen, Systemstatus anstatt Systeminteraktionen zu testen, werden, wenn überhaupt, sparsam mit Mocks umgehen.

Test verdoppelt sich

Fakes, Stubs und Mocks gehören alle zur Kategorie Test Doubles. Ein Test Double ist jedes Objekt oder System, das Sie in einem Test verwenden statt ​​etwas anderes. Die meisten automatisierten Softwaretests beinhalten die Verwendung von Test-Doubles der einen oder anderen Art. Einige andere Arten von Test-Doubles umfassen Dummy-Werte , Spione und I/O Schwarze Löcher .

11
Daniel Pryden

Um die Verwendung von Stubs und Mock 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 hat, Protokolle zu drucken. Es muss nicht nur mit einem Webservice gesprochen werden. Wenn der Webservice einen Fehler ausgibt, muss LogAnalyzer den Fehler in einer anderen externen Abhängigkeit protokollieren und ihn per E-Mail an den Webservice-Administrator senden.

Hier ist die Logik, die wir in LogAnalyzer testen möchten:

if(fileName.Length<8)
{
 try
  {
    service.LogError("Filename too short:" + fileName);
  }
 catch (Exception e)
  {
    email.SendEmail("a","subject",e.Message);
  }
}

Wie testen Sie, ob LogAnalyzer den E-Mail-Dienst korrekt aufruft, wenn der Web-Service eine Ausnahme auslöst? Hier sind die Fragen, mit denen wir konfrontiert sind:

  • Wie können wir den Webservice ersetzen?

  • Wie können wir eine Ausnahme vom Webservice simulieren, damit wir den Anruf beim E-Mail-Service testen können?

  • Woher wissen wir, dass der E-Mail-Dienst richtig oder um All aufgerufen wurde?

Die ersten beiden Fragen können wir mit mit einem Stub für den Webservice bearbeiten. Um das dritte Problem zu lösen, können wir ein Mock-Objekt für den E-Mail-Dienst verwenden.

Eine Fälschung ist ein Oberbegriff, der verwendet werden kann, um einen Stub oder einen Schein zu beschreiben. In unserem Test haben wir zwei Fälschungen. Einer wird der E-Mail-Service-Mock sein, mit dem wir überprüfen, ob die korrekten Parameter an den E-Mail-Service gesendet wurden. Der andere wird ein Stub sein, mit dem wir eine Ausnahme simulieren, die vom Webservice ausgelöst wird. Dies ist ein Stub, da wir die Web-Service-Fälschung nicht zur Überprüfung des Testergebnisses verwenden, nur um sicherzustellen, dass der Test ordnungsgemäß ausgeführt wird. Der E-Mail-Dienst ist ein Mock, weil wir dagegen behaupten, dass er korrekt aufgerufen wurde.

[TestFixture]
public class LogAnalyzer2Tests
{
[Test]
 public void Analyze_WebServiceThrows_SendsEmail()
 {
   StubService stubService = new StubService();
   stubService.ToThrow= new Exception("fake exception");
   MockEmailService mockEmail = new MockEmailService();

   LogAnalyzer2 log = new LogAnalyzer2();
   log.Service = stubService
   log.Email=mockEmail;
   string tooShortFileName="abc.ext";
   log.Analyze(tooShortFileName);

   Assert.AreEqual("a",mockEmail.To); //MOCKING USED
   Assert.AreEqual("fake exception",mockEmail.Body); //MOCKING USED
   Assert.AreEqual("subject",mockEmail.Subject);

 }
}
7
nanospeck

Es geht darum, die Tests ausdrucksstark zu machen. Ich setze Erwartungen an ein Mock, wenn der Test eine Beziehung zwischen zwei Objekten beschreiben soll. Ich stubre die Rückgabewerte, wenn ich ein unterstützendes Objekt aufstelle, um mich zu dem interessanten Verhalten im Test zu bringen.

5
Steve Freeman

Wenn Sie mit Arrange-Act-Assert vertraut sind, können Sie den Unterschied zwischen Stub und Mock, der für Sie nützlich sein könnte, erklären, indem Stubs zum Arrangement-Abschnitt gehören, wie zum Anordnen des Eingabezustands und Mocks der Assert-Abschnitt, wie sie für die Durchsetzung von Ergebnissen gegen sind.

Dummys machen nichts. Sie dienen nur zum Auffüllen von Parameterlisten, damit Sie keine undefinierten oder null Fehler erhalten. Sie sind auch vorhanden, um den Type Checker in streng typisierten Sprachen zu erfüllen, sodass Sie kompilieren und ausführen können.

2
Sammi

das, was Sie darauf behaupten, heißt ein mock object und alles andere, was gerade beim Testlauf geholfen hat, ist ein stub .

1

stub und fake sind Objekte, bei denen sie ihre Antwort basierend auf Eingabeparametern variieren können. Der Hauptunterschied zwischen ihnen ist, dass eine Fälschung einer Implementierung in der realen Welt näher ist als ein Stub. Stubs enthalten im Wesentlichen hart codierte Antworten auf eine erwartete Anforderung. Lass ein Beispiel sehen: 

public class MyUnitTest {

 @Test
 public void testConcatenate() {
  StubDependency stubDependency = new StubDependency();
  int result = stubDependency.toNumber("one", "two");
  assertEquals("onetwo", result);
 }
}

public class StubDependency() {
 public int toNumber(string param) {
  if (param == “one”) {
   return 1;
  }
  if (param == “two”) {
   return 2;
  }
 }
}

Ein Schein ist ein Aufstieg 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 auf diese Informationen reagieren. Mocks kennen im Allgemeinen den Kontext jedes Anrufs und können in verschiedenen Situationen unterschiedlich reagieren. Aus diesem Grund erfordern Mocks ein gewisses Wissen über die Klasse, die sie verspotten. Ein Stub kann im Allgemeinen nicht nachvollziehen, wie oft eine Methode aufgerufen wurde oder in welcher Reihenfolge eine Sequenz von Methoden aufgerufen wurde. Ein Schein sieht aus wie:

public class MockADependency {

 private int ShouldCallTwice;
 private boolean ShouldCallAtEnd;
 private boolean ShouldCallFirst;

 public int StringToInteger(String s) {
  if (s == "abc") {
   return 1;
  }
  if (s == "xyz") {
   return 2;
  }
  return 0;
 }

 public void ShouldCallFirst() {
  if ((ShouldCallTwice > 0) || ShouldCallAtEnd)
   throw new AssertionException("ShouldCallFirst not first thod called");
  ShouldCallFirst = true;
 }

 public int ShouldCallTwice(string s) {
  if (!ShouldCallFirst)
   throw new AssertionException("ShouldCallTwice called before ShouldCallFirst");
  if (ShouldCallAtEnd)
   throw new AssertionException("ShouldCallTwice called after ShouldCallAtEnd");
  if (ShouldCallTwice >= 2)
   throw new AssertionException("ShouldCallTwice called more than twice");
  ShouldCallTwice++;
  return StringToInteger(s);
 }

 public void ShouldCallAtEnd() {
  if (!ShouldCallFirst)
   throw new AssertionException("ShouldCallAtEnd called before ShouldCallFirst");
  if (ShouldCallTwice != 2) throw new AssertionException("ShouldCallTwice not called twice");
  ShouldCallAtEnd = true;
 }

}

Ich habe viel aus der folgenden Quelle gelernt, mit einer hervorragenden Erklärung von Robert C. Martin (Onkel Bob):

Der kleine Spötter auf dem Clean Code Blog

Es erklärt die Unterschiede und Feinheiten von

  • dummies
  • test verdoppelt sich
  • stummel
  • spione
  • (wahr) verspottet
  • fälschungen

Es erwähnt auch Martin Fowler und erklärt ein bisschen Software-Test-Geschichte.

Auf keinen Fall beabsichtige ich, diese Frage mit diesem Link als echte Antwort zu beantworten. Es hat mir jedoch geholfen, die Konzepte des Verspottens und Spionierens besser zu verstehen, und ich beantworte dies in der Hoffnung, dass es mehr Menschen hilft.

0
Erik