Was bringt es, die Abhängigkeiten im Komponententest zu verspotten?

8

Ich arbeite an Komponententests für meine Controller- und Service-Layer (C #, MVC). Und ich benutze Moq dll für das Mocking der Real / Abhängigkeit Objekte in Unit-Tests.

Aber ich bin etwas verwirrt in Bezug auf die Abhängigkeiten oder reale Objekte verspotten. Nehmen wir ein Beispiel für die Testmethode unterhalb der Einheit: -

%Vor%

In der obigen Komponententestmethode mache ich mich über die GetCustomers-Methode lustig und gebe eine Kundenliste zurück. Was ist schon definiert. Und sieht wie folgt aus:

%Vor%

Und werfen wir einen Blick auf die Behauptung des Kunden über das verspottete Objekt und das tatsächliche Objekt. Behauptung: -

%Vor%

Aber hier verstehe ich nicht, dass es (über Unit-Test) immer gut funktioniert. Bedeutet, dass wir nur (in Assertion) testen, was wir bestanden haben oder was wir zurückgeben (in spottendem Objekt). Und wir wissen, dass das reale / tatsächliche Objekt immer die Liste oder das Objekt zurückgibt, das wir übergeben haben.

Was bedeutet es also, Unit Testing oder Mocking hier zu machen?

    
Pawan 01.04.2014, 10:54
quelle

4 Antworten

5

Der wahre Zweck des Spotts ist es, wahre Isolation zu erreichen.

Angenommen, Sie haben eine Klasse CustomerService , die von CustomerRepository abhängt. Sie schreiben einige Komponententests, die die von CustomerService bereitgestellten Funktionen abdecken. Sie alle gehen durch.

Einen Monat später wurden ein paar Änderungen vorgenommen, und plötzlich beginnen Ihre CustomerServices Unit-Tests - und Sie müssen herausfinden, wo das Problem liegt.

Sie nehmen also an:

  

Da ein Komponententest, der CustomerServices testet, fehlschlägt, muss das Problem in dieser Klasse liegen !!

Richtig? Falsch! Das Problem könnte entweder in CustomerServices oder in irgendeiner seiner Abhängigkeiten liegen, d. H.% Co_de%. Wenn eine der Abhängigkeiten fehlschlägt, besteht die Möglichkeit, dass die zu testende Klasse ebenfalls fehlschlägt.

Stellen Sie sich nun eine riesige Kette von Abhängigkeiten vor: CustomerRepository hängt von A ab, B hängt von B ab, ... C hängt von Y ab. Wenn ein Fehler in Z , all auftritt, schlägt Ihr Komponententest fehl.

Und deshalb müssen Sie die zu testende Klasse von ihren Abhängigkeiten isolieren (sei es ein Domänenobjekt, eine Datenbankverbindung, Dateiressourcen usw.). Sie möchten eine Einheit testen.

    
dcastro 01.04.2014, 11:07
quelle
1

Ihr Beispiel ist zu einfach, um den wirklichen Vorteil des Spottes zu demonstrieren. Das liegt daran, dass Ihre zu testende Logik nicht viel mehr tut, als einige Daten zurückzugeben.

Aber stellen Sie sich als ein Beispiel vor, dass Ihre Logik etwas basierend auf der Wanduhrzeit gemacht hat, sagen wir, dass jede Stunde ein Prozess geplant wird. In einer solchen Situation können Sie die Zeitquelle verspotten, indem Sie diese Logik testen, so dass Ihr Test nicht stundenlang ausgeführt werden muss, bis die Zeit verstrichen ist.

    
quelle
1

Zusätzlich zu dem, was bereits gesagt wurde:

Wir können Klassen ohne Abhängigkeiten haben. Und das einzige, was wir haben, ist Unit Testing ohne Mocks und Stubs.

Wenn wir Abhängigkeiten haben, gibt es verschiedene Arten von ihnen:

  • Service, den unsere Klasse meist auf "fire and forget" -Weise verwendet, d. h. Dienste, die den Kontrollfluss des konsumierenden Codes nicht beeinflussen.

Wir können diese (und alle anderen) Dienste verspotten, um zu testen, ob sie korrekt aufgerufen wurden (Integrationstest) oder einfach zum Injizieren, wie es unser Code erfordern könnte.

  • Zwei-Wege-Dienste, die Ergebnisse liefern, aber keine internen haben Zustand und beeinflussen nicht den Zustand des Systems. Sie können komplexe Datentransformationen genannt werden.

Indem Sie sich über diese Dienste lustig machen, können Sie Ihre Erwartungen bezüglich des Codeverhaltens für verschiedene Varianten der Dienstimplementierung testen, ohne sie alle aufheben zu müssen.

  • Dienste, die den Zustand des Systems beeinflussen oder von der realen Welt abhängen Phänomene oder etwas außerhalb Ihrer Kontrolle. '@ 500 - Interner Serverfehler' gab ein gutes Beispiel für den Zeitdienst.

Mit Mocking kannst du die Zeit mit der Geschwindigkeit (und der Richtung) fließen lassen, die benötigt wird.
Ein anderes Beispiel ist die Arbeit mit der DB. Beim Komponententest ist es normalerweise wünschenswert, den DB-Zustand nicht zu ändern, was beim Funktionstest nicht zutrifft. Für solche Dienste ist "Isolation" die wichtigste (aber nicht die einzige) Motivation, sich zu verspotten.

  • Dienste mit internem Status, von dem Ihr Code abhängt.

Betrachten Sie Entity Framework:
Wenn SaveChanges() aufgerufen wird, passieren viele Dinge hinter der Szene. EF erkennt Änderungen und repariert Navigationseigenschaften. Auch EF erlaubt Ihnen nicht, mehrere Entitäten mit demselben Schlüssel hinzuzufügen.
Offensichtlich kann es sehr schwierig sein, das Verhalten und die Komplexität solcher Abhängigkeiten zu verspotten ... aber normalerweise haben Sie es nicht, wenn sie gut entworfen sind. Wenn Sie sich stark auf die Funktionalität verlassen, die eine Komponente bietet, können Sie diese Abhängigkeit kaum ersetzen. Was wahrscheinlich benötigt wird, ist wieder Isolation. Sie wollen keine Spuren hinterlassen, wenn Sie testen, also ist Butter Ansatz EF zu sagen, dass Sie keine echte DB verwenden sollen. Ja, Abhängigkeit bedeutet mehr als nur eine Schnittstelle. Meistens sind es nicht die Methoden-Signaturen, sondern der Vertrag für das erwartete Verhalten. Zum Beispiel hat IDbConnection Open() und Close() Methoden was eine bestimmte Folge von Anrufen impliziert.

Sicher, es ist keine strenge Klassifizierung. Besser, es als Extreme zu behandeln.

@dcastro schreibt: You want to test a unit. Doch die Aussage beantwortet nicht die Frage, ob Sie sollten.
Lassen Sie Integrationstests nicht diskontieren. Manchmal ist es in Ordnung zu wissen, dass ein Teil des Systems fehlerhaft ist Zum Beispiel mit der Kette von Abhängigkeiten, die von @dcastro gegeben werden, können wir versuchen, den Ort zu finden, wo die Tasche wahrscheinlich ist:

Angenommen, Z ist eine endgültige Abhängigkeit. Wir erstellen Unit-Tests ohne Mocks dafür. Alle Randbedingungen sind bekannt. 100% Abdeckung ist hier ein Muss. Danach sagen wir, dass Z richtig funktioniert. Und wenn Z fehlschlägt, müssen unsere Unit-Tests dies anzeigen.
Das Analog kommt aus dem Maschinenbau. Niemand testet jede Schraube und Schraube, wenn er ein Flugzeug baut.
Statistische Methoden werden verwendet, um mit einiger Sicherheit zu beweisen, dass Fabrik, die die Details produziert, gut funktioniert.

Auf der anderen Seite ist es für sehr kritische Teile Ihres Systems sinnvoll, Zeit zu verbringen und komplexes Verhalten der Abhängigkeit zu verspotten. Ja, je komplexer die weniger wartungsfähigen Tests sind. Und hier würde ich sie lieber als die Spezifikationsüberprüfungen bezeichnen.
Ja, Ihre API und Tests können beide falsch sein, aber Code Review und andere Formen des Testens können die Korrektheit des Codes zu einem gewissen Grad sicherstellen. Und sobald diese Tests fehlschlagen, nachdem einige Änderungen vorgenommen wurden, müssen Sie entweder die Spezifikationen und die entsprechenden Tests ändern oder den Fehler finden und den Fall mit dem Test abdecken.

Ich empfehle Ihnen, Roy's Videos anzuschauen: Ссылка

    
Pavel Voronin 01.04.2014 16:20
quelle
0

In diesem Fall hat es Ihnen das Spotten ermöglicht, eine Datenbankverbindung zu fälschen, so dass Sie einen Test vor Ort und im Speicher ausführen können, ohne sich auf eine zusätzliche Ressource, d. h. die Datenbank, verlassen zu müssen. Dieser Test besagt, dass beim Aufruf eines Dienstes eine entsprechende Methode von DAL aufgerufen wird.

Jedoch sind die späteren Behauptungen der Liste und der Werte in der Liste nicht notwendig. Wie Sie richtig bemerkt haben, behaupten Sie nur, dass die Werte, die Sie "verspottet" haben, zurückgegeben werden. Dies wäre innerhalb des Mocking-Frameworks selbst nützlich, um zu behaupten, dass sich die Mocking-Methoden wie erwartet verhalten. Aber in deinem Code ist es einfach exzessiv.

Im allgemeinen Fall erlauben Spott einem:

  • Testverhalten (wenn etwas passiert, wird eine bestimmte Methode ausgeführt)
  • Gefälschte Ressourcen (z. B. E-Mail-Server, Webserver, HTTP-API-Anfrage / Antwort, Datenbank)

Im Gegensatz dazu erlauben Unit-Tests ohne Mocking normalerweise, den Zustand zu testen. Das heißt, Sie können eine Änderung in einem Zustand eines Objekts feststellen, wenn eine bestimmte Methode aufgerufen wurde.

    
oleksii 01.04.2014 11:13
quelle

Tags und Links