Warum sollte ich in Unit Testing zweimal ein Repository erstellen?

10

Neulich habe ich ein wenig über Unit Testing gelesen und einige Beispiele gesehen, in denen Leute eine Repository-Schnittstelle (dh IExampleRepository) erstellen und dann das echte Repository ( public class ExampleRepository : IExampleRepository) und ein Repository für Unit-Tests ( FakeExampleRepository : IExampleRepository) erstellen .

In der IExampleRepositoryimplementierten sie die gleichen Methoden wie in der ExampleRepository, jedoch mit unterschiedlichen Linq-Abfragen.

Was genau ist hier das Ziel? Ich dachte, ein Teil des Unit-Tests Ihres Codes besteht darin, sicherzustellen, dass eine Methode korrekt funktioniert. Aber wie viel Sinn macht der Test, wenn ich zwei völlig unterschiedliche Abfragen verwende, eine für "echt" und eine im Test?

jao
quelle

Antworten:

8

Eines der Ziele von Unit-Tests ist es, jeweils nur eine Sache zu testen, dh eine einzelne Klasse und Methode. Wenn das Repository selbst nicht getestet wird, verspotten Sie dies normalerweise auf irgendeine Weise, um nur die Logik in Ihrer Methode / Klasse zu testen.

Das heißt, Sie müssen auch mit einem "echten" Repository * testen, dies wird jedoch normalerweise in einem Integrations- / Systemtest durchgeführt

* offensichtlich echt wie im Repo zum Testen eingerichtet, hoffentlich nicht zB die Produktions-DB.

jk.
quelle
Beim Testen von Einheiten werde ich die Methode selbst nicht testen, um sicherzustellen, dass sie die richtigen Werte zurückgibt (basierend auf einem gefälschten / verspotteten Datensatz).
Jao
Ja, Sie werden die Methode selbst testen, aber nur den Code in der Methode. Code in anderen Objekten sollte in anderen Komponententests behandelt werden. Die Interaktion mehrerer Objekte sollte in Integrationstests oder Tests auf höherer Ebene behandelt werden
jk.
1
Ok, wenn ich das richtig verstehe, sollte ich beim Testen der Repositorys das ursprüngliche Repository verwenden. Ich muss sie nicht testen, wenn ich Unit-Tests für die Controller schreibe (im Fall von Asp.Net MVC)
jao
4
@Theomax Abhängig vom Kontext: Wenn Sie eine Softwarekomponente testen, die nicht Ihre ist ExampleRepository, ist es am besten, ein Modell zu verwenden. Die Rechtfertigung ist, dass Sie nicht das Repository testen, sondern etwas anderes.
Andres F.
5
@Theomax So erweitern Sie den Kommentar von AndresF.: Wenn Sie Unit-Tests durchführen ExampleRepository, verwenden Sie das Original . Wenn Sie Unit-Tests durchführen RepositoryController, sollte nur a verwendet werden FakeExampleRepository, das vorgegebene Werte zurückgibt. Auf diese Weise, wenn ein Fehler einschleicht zu ExampleRepository, nur dass Unit - Test fehl - RepositoryController‚s - Tests werden auch weiterhin erfolgreich zu sein , so dass Sie wissen , dass es nicht um einen Fehler gibt. Wenn der Controller das echte Repository verwenden würde, würden beide fehlschlagen und Sie würden nicht wissen, ob Sie 1 oder 2 Fehler hatten.
Izkata
5

Ich stimme den beiden Antworten von jk zu. und Jan Hudec - sie geben einige wirklich gute Informationen. Aber ich dachte, ich würde ein bisschen hinzufügen.

Ihre erste Frage ("Was genau ist das Ziel hier?") Ist wichtig. In dem von Ihnen beschriebenen Fall besteht das eigentliche Ziel darin, die Klassen zu testen, die die IExampleRepositorySchnittstelle verwenden, und nicht die Repository-Implementierungen. Durch das Erstellen von FakeExampleRepositorykönnen Sie diese Clientklassen testen, ohne sich um die Details der realen Repository-Klasse kümmern zu müssen.

Dies gilt insbesondere dann, wenn das Objekt, das Sie einrichten möchten, das Testen erschwert (z. B. Zugriff auf das Dateisystem, Aufruf eines Webservices oder Kommunikation mit einer Datenbank). Durch die Verwendung von Schnittstellen (und anderen derartigen Techniken) halten Sie die Kopplung niedrig. Daher muss die Klasse Xnur über die Schnittstelle und nicht über die Implementierungsdetails Bescheid wissen. Das Ziel ist es sicherzustellen, dass die Klasse Xdas Richtige tut.

Das Verspotten (oder Stubben, Fälschen ... es gibt nuancierte Unterschiede) ist ein leistungsstarkes Werkzeug für Unit-Tests und TDD. Es kann jedoch schwierig sein, diese Implementierungen manuell zu erstellen und zu warten. Daher haben die meisten Sprachen jetzt verspottete Bibliotheken, um zu helfen. Da Sie C # verwenden, würde ich Moq empfehlen, da es einfach und sehr leistungsfähig ist. Anschließend können Sie die Schnittstelle testen, ohne zusätzlichen Code für die Scheinimplementierungen zu stapeln.

Allan
quelle
the real objective is to test the classes that are utilizing the IExampleRepository interfacedas ist nicht unbedingt wahr. Ziel ist es, es unabhängig vom IExampleRepository zu testen . +1 für die Empfehlung eines guten Isolationsrahmens.
StuperUser
1
Ich stimme dir nicht zu. Es ist nicht unabhängig von, IExampleRepositoryda die zu testende Klasse an diese Schnittstelle gekoppelt ist. Es ist jedoch unabhängig von Implementierungen der Schnittstelle. Ich gebe zu, dass meine Erklärung wahrscheinlich etwas mehr Finesse gebrauchen könnte. :)
Allan
5

Was genau ist hier das Ziel?

Isolation.

Die Idee einer Einheit testet die kleinstmögliche zu testen Einheit des Codes. Sie tun dies, indem Sie es von allen anderen Produktionscodes im Test isolieren .

Durch das Erstellen gefälschter Klassen ist der einzige Produktionscode die zu testende Klasse.

Wenn Sie ein gefälschtes Repository ordnungsgemäß erstellen und der Test fehlschlägt, wissen Sie, dass das Problem beim zu testenden Code liegt. Dies gibt Ihnen den Vorteil einer kostenlosen Diagnose.

Schauen Sie sich Isolations-Frameworks an (wie Moq, wie von @Allan vorgeschlagen), um diese Fälschungen schnell zu generieren, um Testbedingungen einzurichten und sie zur Durchsetzung zu verwenden.

StuperUser
quelle
Weitere Details zu Fälschungen, Verspottungen
StuperUser
4

Es gibt drei Gründe, warum Sie möglicherweise eine Scheininstanz für den Komponententest bereitstellen möchten:

  1. Sie möchten den Umfang des Tests einschränken, damit der Test nicht von Fehlern im Depndee betroffen ist, möglicherweise weil er noch nicht abgeschlossen oder nicht stabil ist oder wenn Sie nicht möchten, dass Fehler in den Tests anderer Personen Ihre Tests beeinflussen.
  2. Der Abhängige ist kompliziert einzurichten. Beispielsweise wird die Datenzugriffsschicht häufig verspottet, da für die eigentliche eine Testdatenbank eingerichtet werden muss. Sie müssen noch die reale Datenzugriffsschicht testen, können jedoch die kostspielige Einrichtung beim Debuggen anderer Dinge begrenzen.
  3. Um zu testen, ob die abhängige Klasse ordnungsgemäß auf verschiedene Arten von Fehlern reagiert, geben Sie eine Scheinversion an, die alle möglichen falschen Antworten zurückgibt. Weil viele Fehlermodi ziemlich schwer zu reproduzieren sind, aber dennoch getestet werden sollten.
Jan Hudec
quelle