Java >> Java Tutorial >  >> Tag >> Spring

Der beste Weg, das Spring MVC Test Framework zu konfigurieren, Teil Eins

Bevor wir Komponententests für Spring MVC-Controller schreiben können, müssen wir das zu testende System (auch bekannt als Spring MVC Test Framework) konfigurieren. Leider müssen wir, bevor wir den Code schreiben können, der das Spring MVC Test-Framework konfiguriert, in der Lage sein, die beste Methode zum Konfigurieren unserer Komponententests auszuwählen.

Nachdem wir diesen Blogbeitrag fertiggestellt haben, werden wir:

  • Kann die Techniken identifizieren, die wir verwenden können, wenn wir das Spring MVC Test-Framework konfigurieren möchten.
  • Kann die beste Methode zum Konfigurieren des Spring MVC Test-Frameworks auswählen, wenn wir Einheitentests schreiben.

Fangen wir an.

Welche Möglichkeiten haben wir?

Wenn wir das Spring MVC Test Framework konfigurieren, müssen wir einen neuen MockMvc erstellen -Objekt, mit dem wir HTTP-Anforderungen an das zu testende System senden können. Wir können dieses Objekt erstellen, indem wir den static verwenden Factory-Methoden der MockMvcBuilders Klasse. Wenn wir den MockMvcBuilders verwenden Klasse können wir das Spring MVC Test Framework mit einer dieser beiden Optionen konfigurieren:

  • Die kontextbasierte Konfiguration der Webanwendung lädt den Spring-Anwendungskontext mithilfe der angegebenen Java-Konfigurationsklassen oder XML-Konfigurationsdateien und konfiguriert das zu testende System mithilfe des geladenen Anwendungskontexts.
  • Die eigenständige Konfiguration ermöglicht es uns, die Spring MVC-Infrastruktur programmgesteuert zu konfigurieren. Diese Option bietet die Mindestkonfiguration, die DispatcherServlet zulässt um HTTP-Anforderungen zu bedienen, die von Spring MVC-Controllern verarbeitet werden. Wir können diese Konfiguration natürlich anpassen, indem wir eine fließende API verwenden.

Als nächstes werfen wir einen Blick auf die Eigenschaften guter Komponententests.

Die Eigenschaften guter Komponententests

Bevor wir den besten Weg zum Konfigurieren des Spring MVC-Testframeworks ermitteln können, müssen wir unsere Anforderungen auflisten und die Konfigurationsoption auswählen, die unsere Anforderungen erfüllt. Wenn wir Unit-Tests schreiben, können wir unsere Anforderungen identifizieren, indem wir die Merkmale guter Unit-Tests identifizieren.

Ein guter Komponententest ist:

Unabhängig und isoliert . Ein Komponententest darf nicht von der Ausführungsreihenfolge anderer Komponententests abhängen und muss einen sauberen Zustand haben, der nicht mit anderen Komponententests geteilt wird. Außerdem müssen wir das zu testende System von seinen externen Abhängigkeiten wie HTTP-APIs oder Datenbanken isolieren.

Wiederholbar . Ein Unit-Test muss deterministisch sein. Das heißt, wenn wir das zu testende System oder den aufgerufenen Unit-Test nicht geändert haben, muss das Ergebnis des Unit-Tests jedes Mal gleich sein, wenn wir ihn ausführen.

Kein (zwangsläufig) Klassentest . Einige Leute denken, dass ein Unit-Test nur eine Methode einer Klasse testen muss. Es gibt viele Situationen, in denen dieser Ansatz nützlich ist, aber ich denke, dass es auch viele Situationen gibt, in denen wir die Größe der getesteten Einheit erhöhen müssen, weil uns dieser Ansatz dabei hilft, aussagekräftigere Unit-Tests zu schreiben. Zum Beispiel:

Erstens, wenn wir Unit-Tests für einen Dienst schreiben, der Informationen an ein externes System überträgt, indem er HTTP-Anfragen mit RestTemplate sendet , sollten wir WireMock verwenden, da wir damit überprüfen können, ob die richtige HTTP-Anforderung an die externe API gesendet wurde, als unser Komponententest die getestete Methode aufrief.

Wenn wir sogenannte Klassentests schreiben wollen, können wir natürlich auch die RestTemplate ersetzen Objekt mit einem Mock. Wenn wir diese Technik verwenden, schreiben wir flache Tests, weil wir nur überprüfen können, ob das zu testende System die richtige Methode des RestTemplate aufruft Klasse mithilfe der erwarteten Methodenparameter. Das bedeutet, dass wir nicht sicher sein können, dass das zu testende System die richtige HTTP-Anforderung an die externe HTTP-API sendet.

Zweitens sollten wir beim Schreiben von Komponententests für einen Spring MVC-Controller das Spring MVC Test-Framework verwenden, da es uns ermöglicht, schnelle Tests für das vollständige Spring MVC-Laufzeitverhalten zu schreiben. Mit anderen Worten, wir können sicherstellen, dass unsere HTTP-Anforderungen von der richtigen Controller-Methode verarbeitet werden, überprüfen, ob die Methodenparameter unserer Controller-Methode aus der eingehenden HTTP-Anforderung analysiert werden, sicherstellen, dass unsere Validierungslogik wie erwartet funktioniert, und Zusicherungen für schreiben die zurückgegebene HTTP-Antwort.

Natürlich können wir auch einen sogenannten Klassentest schreiben, indem wir einen Unit-Test schreiben, der die getestete Controller-Methode aufruft. Auch wenn diese Tests uns helfen, einige Teile unserer Controller-Methode zu testen, sind sie nicht annähernd so nützlich wie die Tests, die das Spring MVC-Framework verwenden, da Klassentests die getestete Controller-Methode nicht über ihre "wahre" API aufrufen ( HTTP). Aus diesem Grund können uns Klassentests nicht dabei helfen, zu überprüfen, ob unsere Spring MVC-Controller wie erwartet funktionieren.

Ein Design-Tool . Es ist allgemein bekannt, dass Unit-Tests uns bei TDD dabei helfen, so wenige Zeilen Produktionscode wie möglich zu schreiben. Auch wenn dies nützlich ist, denke ich, dass Unit-Tests einen weiteren wichtigen und oft übersehenen Vorteil haben. Unit-Tests können es einfacher machen zu erkennen, ob das zu testende System zu viele Abhängigkeiten hat. Wenn wir das zu testende System und seine Abhängigkeiten manuell konfigurieren und feststellen, dass es viel Arbeit kostet, hat das zu testende System zu viele Abhängigkeiten oder die Größe der getesteten Einheit ist zu groß.

Schnell . Eine Unit-Test-Suite ist im Grunde unsere erste Verteidigungslinie und sollte deshalb so schnell wie möglich sein. Dies ist (offensichtlich) wichtig, wenn wir TDD machen, weil langsame Tests unsere Rückkopplungsschleife länger machen, als sie sein sollte. Dies ist jedoch auch dann von entscheidender Bedeutung, wenn wir kein TDD verwenden, da Entwickler dazu neigen, langsame Testsuiten zu vermeiden. Das Problem ist, dass lange Testläufe im Grunde Ablenkungen sind, die es schwierig machen, sich auf das Schreiben von Code zu konzentrieren, anstatt Reddit, Twitter oder HackerNews zu durchsuchen.

Wir haben nun die Anforderungen unserer Unit-Tests identifiziert. Lassen Sie uns weitermachen und herausfinden, wie wir das Spring MVC Test-Framework am besten konfigurieren, wenn wir Unit-Tests schreiben.

Auswahl der besten Methode zur Konfiguration des Spring MVC-Testframeworks

Ich argumentiere, dass wir, wenn wir Unit-Tests schreiben wollen, die unsere Anforderungen erfüllen, unsere Unit-Tests mit der Standalone-Konfiguration konfigurieren müssen. Die eigenständige (auch programmgesteuerte) Konfiguration hat die folgenden Vorteile gegenüber der kontextbasierten Konfiguration der Webanwendung:

Zuerst , da die eigenständige Konfiguration die Mindestkonfiguration bietet, die mithilfe einer fließenden API angepasst werden kann, ist es einfach, die Größe der getesteten Einheit auszuwählen. Das bedeutet:

  • Wir müssen keine sogenannten Klassentests schreiben, wenn das Schreiben keinen Sinn macht. Wenn wir beispielsweise Unit-Tests für eine Controller-Methode schreiben, die einfach die aus der Datenbank gefundenen Informationen zurückgibt, können wir eine echte Serviceklasse verwenden und ihre Abhängigkeiten durch Testdoubles ersetzen. Wenn wir diesen Ansatz verwenden, können wir aussagekräftigere Unit-Tests für unsere Controller-Methode schreiben.
  • Wenn ein Testfall fehlschlägt, ist es einfach, den fehlgeschlagenen Testfall zu debuggen, da wir wissen, welche Komponenten ausgeführt werden, wenn der fehlgeschlagene Testfall das zu testende System aufruft.

Zweiter müssen wir die externen Abhängigkeiten des zu testenden Systems (auch bekannt als Testdoubles) in unserer Testklasse erstellen und konfigurieren, bevor eine Testmethode ausgeführt wird. Das mag wie ein Nachteil klingen, ist aber aus diesen zwei Gründen tatsächlich ein großer Vorteil:

  • Da unsere Testdoppel erstellt werden, bevor eine Testmethode ausgeführt wird, erhält jede Testmethode "saubere" Testdoppel. Mit anderen Worten, dieser Ansatz hilft uns, deterministische Komponententests zu schreiben und sicherzustellen, dass ein Komponententest einen sauberen Zustand hat, der nicht mit anderen Komponententests geteilt wird.
  • Wir können unsere Tests als Design-Tool verwenden. Wie ich bereits erwähnt habe, wenn wir feststellen, dass die Konfiguration dieser Abhängigkeiten zu viel Arbeit erfordert, hat das zu testende System zu viele Abhängigkeiten oder die Größe der getesteten Einheit ist zu groß.

Dritter , unser Konfigurationscode ist schnell, da er den Spring-Anwendungskontext nicht lädt und keine Spring-Beans aus dem Klassenpfad scannt.

Der Nachteil der eigenständigen Konfiguration besteht darin, dass unsere Komponententests möglicherweise eine andere Konfiguration verwenden als die Anwendung, die in der Produktionsumgebung bereitgestellt wird.

Lassen Sie uns weitermachen und herausfinden, welche Komponente wir in das zu testende System aufnehmen sollten.

Welche Komponenten brauchen wir?

Wenn wir die eigenständige Konfiguration verwenden, können wir die Komponenten auswählen, die wir in das zu testende System aufnehmen möchten, indem wir die API von StandaloneMockMvcBuilder verwenden Klasse. Das ist Segen und Fluch zugleich. Wenn wir die Flexibilität nutzen, die die Standalone-Konfiguration bietet, können wir mit diesen beiden Problemen konfrontiert werden:

Zuerst , wenn wir eine Komponente in das zu testende System aufnehmen, geht die Person, die unseren Testcode liest, davon aus, dass die Komponente von unseren Testfällen benötigt wird. Ist dies nicht der Fall, führt unsere Konfiguration in die Irre und macht unsere Tests schwer lesbar. Erschwerend kommt hinzu, wenn die Person, die unseren Testcode liest, ihn liest, weil ein Testfall fehlgeschlagen ist, kann eine irreführende Konfiguration diese Person viel Zeit kosten.

Zweiter , weil die StandaloneMockMvcBuilder -Klasse es uns ermöglicht, so ziemlich jede Komponente zu konfigurieren, die vom Spring MVC-Framework bereitgestellt wird, kann es sehr verlockend sein, diese Gelegenheit zu nutzen. Wenn wir uns jedoch dafür entscheiden, schreiben wir am Ende Tests, die eigentlich keine Unit-Tests sind.

Diese Tests sind normalerweise schwer zu schreiben, weil wir zu viele Zusicherungen schreiben müssen UND diese Tests sind auch schwer zu warten, weil wir die Konfiguration unserer Anwendung und die Konfiguration synchronisieren müssen, die wir verwenden, wenn wir unsere Einheitentests ausführen.

Deshalb denke ich, dass wir die Anzahl der benutzerdefinierten Komponenten, die wir in das zu testende System einbauen, minimieren sollten. Außerdem sollten wir nicht in jeder Testklasse dieselbe Konfiguration verwenden, da höchstwahrscheinlich unterschiedliche Controller nicht dieselben Komponenten benötigen.

Wir können jetzt die beste Methode zum Konfigurieren des Spring MVC Test-Frameworks auswählen, wenn wir Komponententests schreiben. Fassen wir zusammen, was wir aus diesem Blogbeitrag gelernt haben.

Zusammenfassung

Dieser Blogbeitrag hat uns sieben Dinge beigebracht:

  • Wir können das Spring MVC Test Framework konfigurieren, indem wir die eigenständige Konfiguration oder die kontextbasierte Konfiguration der Webanwendung verwenden.
  • Die eigenständige Konfiguration bietet eine einfache Möglichkeit, die Größe der getesteten Einheit auszuwählen.
  • Wenn wir die eigenständige Konfiguration verwenden, ist es einfach, deterministische Einheitentests zu schreiben.
  • Die eigenständige Konfiguration hilft uns sicherzustellen, dass ein Komponententest einen sauberen Zustand hat, der nicht mit anderen Komponententests geteilt wird.
  • Wenn wir die Standalone-Konfiguration verwenden, können wir unsere Unit-Tests als Design-Tool verwenden.
  • Die eigenständige Konfiguration ermöglicht es uns, schnelle Komponententests zu schreiben, da sie den Spring-Anwendungskontext nicht lädt und keine Spring-Beans aus dem Klassenpfad scannt.
  • Wir sollten die Anzahl der benutzerdefinierten Komponenten minimieren, die wir in das zu testende System integrieren.

Java-Tag