Parasoft C/C++test 2022.2 unterstützt das neue MISRA C:2012 Amendment 3 und eine Entwurfsversion von MISRA C++ 202x. Erfahren Sie mehr >>

Vorgehensweise beim Testen von Microservices

Von Nathan Jakubiak

5. Juli 2018

11  min lesen

In vielerlei Hinsicht unterscheidet sich das Testen einer Microservices-Anwendung nicht vom Testen einer Anwendung, die mit einer anderen Architektur erstellt wurde. Die einzigartige Herausforderung bei Microservices besteht in der Anzahl der Dienste, aus denen eine Anwendung besteht, sowie in der Anzahl der Abhängigkeiten zwischen den Diensten.

Als Architektur für den Aufbau komplexer Systeme gewinnen Microservices innerhalb der Entwicklergemeinschaft zunehmend an Bedeutung. Während die Leute allmählich verstehen, dass dies nicht das Allheilmittel für alle Probleme der Anwendungsarchitektur ist, können Anwendungen, die Herausforderungen in Bezug auf Abhängigkeiten und Skalierung gemeinsam haben, stark davon profitieren.

Die Akzeptanz von Microservices nimmt zu, aber auch die Probleme, die mit dem Verständnis der Vorgehensweise verbunden sind Mikrodienstleistungen testen. Toby Clemson aus Thought hat einen tollen Job gemacht von Auflisten von Teststrategien Vielleicht möchten Sie es in einer Microservices-Architektur verwenden (siehe seinen Artikel für einen guten Überblick über die verschiedenen Arten von Tests, die Sie möglicherweise erstellen möchten), aber das allgemeine Wissen darüber, wie diese verschiedenen Arten von Tests erstellt und verwaltet werden, steckt noch in den Kinderschuhen .

In vielerlei Hinsicht unterscheidet sich das Testen einer Microservices-Anwendung nicht vom Testen einer Anwendung, die mit einer anderen Architektur erstellt wurde. Microservices verwenden bekannte Technologien wie REST oder Warteschlangen, für die die Softwareindustrie bereits über etablierte Testtools und Best Practices verfügt. Die einzigartige Herausforderung bei Microservices ist die schiere Anzahl von Diensten, aus denen eine Anwendung besteht, sowie die Abhängigkeiten zwischen den Diensten. Darüber hinaus muss jeder Mikrodienst auch dann ordnungsgemäß funktionieren, wenn andere Mikrodienste, von denen sie abhängen, nicht verfügbar sind oder nicht richtig reagieren.

Microservices folgen normalerweise zwei Mustern, wenn sie miteinander interagieren: Orchestrierung und reaktive (Choreografie). Viele Microservices verwenden einen kombinierten „Hybrid“ -Ansatz. In diesem Beitrag werde ich einige Strategien zur Bewältigung einiger der Herausforderungen vorstellen, die sich beim Erstellen automatisierter Tests für Mikrodienste ergeben, die diese unterschiedlichen Muster verwenden, wobei der Schwerpunkt auf Tests für die einzelnen Mikrodienste liegt (im Gegensatz zu End-to-End-Tests der gesamten Anwendung) ).

Testen von orchestrierten Microservices

Ein Mikrodienst, der Orchestrierung verwendet, ruft einen oder mehrere explizite Aufrufe externer Dienste oder Abhängigkeiten auf. Die Anrufe verwenden normalerweise einen synchronen Anforderungs- / Antwortfluss und greifen häufig auf REST-basierte Dienste zu. Wenn die Dienste in einer bestimmten Reihenfolge aufgerufen werden müssen, werden Anrufe an einen nachfolgenden Dienst erst getätigt, wenn eine Antwort auf einen Anruf an einen früheren Dienst eingegangen ist. Da ein Dienst explizit einen anderen aufruft, sind sie eng miteinander verbunden.

In dem oben gezeigten Beispiel ist das Erstellen und Ausführen von Tests für den Portfolio-Mikroservice eine Herausforderung, da der Portfolio-Mikroservice Abhängigkeiten von den Mikrodiensten "Konten und Angebote" aufweist, die zusammen mit dem Portfolio-Mikroservice in der Testumgebung bereitgestellt werden müssen. Der Quotes-Service ist abhängig von einem Drittanbieter-Service, um Aktienkurse in Echtzeit abzurufen, und die von diesem Service zurückgegebenen Daten ändern sich ständig.

Das Verlassen auf Dienste von Drittanbietern oder Dienste, die von verschiedenen Teams entwickelt wurden, trägt erheblich zur Komplexität der Testumgebung bei. Darüber hinaus müssen unerwartete Verhaltensweisen des Portfolio-Dienstes getestet werden, z. B. wenn die Konten- und / oder Angebotsdienste nicht verfügbar sind, langsam reagieren oder mit unerwarteten Daten antworten. Es ist wichtig, dass diese Dienste mit unterschiedlichen unerwarteten Verhaltensweisen reagieren können, um zu überprüfen, ob der Portfolio-Mikroservice die Fehlerbedingungen ordnungsgemäß behandelt.

So vereinfachen Sie das Testen von Microservices-Architekturen

Service-Virtualisierung zur Rettung!

Sie können verwenden Dienstvirtualisierung, um die Antworten zu simulieren der Accounts and Quotes-Microservices. Die Dienstvirtualisierung ermöglicht es Ihnen, virtuelle Versionen der Microservices „Accounts“ und „Quotes“ zu definieren und sie zusammen mit der eigentlichen Instanz des Microservice „Portfolio“ bereitzustellen. Die Virtualisierung von Microservices ähnelt der Virtualisierung jeder anderen Art von Service- oder Anwendungsarchitektur. Es könnte so aussehen:

Sobald dies erledigt ist, kann der Portfolio-Mikroservice unabhängig von seinen beiden Abhängigkeiten getestet werden.

Die nächste Herausforderung besteht darin, verschiedene Umgebungen für verschiedene Fälle zu konfigurieren, z. B. wenn die Konten- und Angebotsdienste erwartete und unerwartete Verhaltensweisen aufweisen. Angenommen, das Team möchte testen, wie sich der Portfolio-Service verhält, wenn entweder der Account-Service oder der Quotes-Service langsam oder mit Fehlerbedingungen reagiert. Dies erfordert möglicherweise die Ausführung von mindestens 5 verschiedenen Testsätzen, von denen jeder eine andere Umgebungskonfiguration aufweist, wobei langsame Antwortzeiten, Fehlerantworten sowie normales und abnormales Verhalten der abhängigen Dienste berücksichtigt werden.

Für jeden Testlauf muss die Umgebung in die richtige Konfiguration gebracht werden, bevor die Tests für diese Konfiguration ausgeführt werden können. In diesem Beispiel haben wir mindestens fünf verschiedene Testläufe, von denen jeder seine eigene Konfiguration für die Umgebung hat. Das Environment Manager-Modul innerhalb von Parasoft Kontinuierliche Testplattform kann diese verschiedenen Umgebungskonfigurationen für Sie verwalten:

Dieser Prozess ist nicht spezifisch für eine Microservices-Architektur - die gleichen Probleme treten bei serviceorientierten Architekturen im Allgemeinen sowie bei monolithischen Anwendungen auf, die möglicherweise nur von einer Handvoll Services abhängen. In einer Microservices-Architektur nimmt die Anzahl der abhängigen Dienste jedoch erheblich zu. In einer Microservices-Umgebung mit zehn oder Hunderten von Diensten ist die Fähigkeit zum Erstellen, Verwalten und programmgesteuerten Wechseln zwischen verschiedenen Umgebungskonfigurationen für verschiedene Testszenarien sehr wichtig und bietet eine erhebliche Zeit- und Arbeitsreduzierung.

Verwalten von API-Änderungen in orchestrierten Microservices

Während Teams ihre Microservices weiterentwickeln, ist es unvermeidlich, dass API-Änderungen an den Services vorgenommen werden. Ein Hauptproblem, das bei API-Änderungen auftritt, besteht darin, die Auswirkungen dieser Änderungen auf die Verbraucher der Dienste zu verstehen.

Wenn ein Team die API für einen von ihm erstellten Microservice ändert, müssen alle Tests, die diesen Microservice validieren, basierend auf den Änderungen in der API aktualisiert werden. Wenn umgekehrt virtuelle Dienste verwendet werden, um abhängige Mikrodienste und eine API für eine dieser abhängigen Mikrodienständerungen zu simulieren, müssen die virtuellen Dienste für den abhängigen Mikrodienst aktualisiert werden, um die Änderungen in der API widerzuspiegeln.

Viele Teams verwenden OpenAPI, RAML oder eine andere Service-Definition, um die APIs für ihre Microservices zu beschreiben. Wenn Dienstdefinitionen verwendet werden, wird das Change Advisor-Modul darin angezeigt Parasoft SOAtest und Parasoft Virtualisieren kann automatisch erkennen, welche APIs geändert wurden, und dann vorhandene Funktionstests oder virtuelle Dienste automatisch umgestalten, um sie mit neuen und / oder entfernten Feldern in der API zu aktualisieren. Teams können aktualisierte Versionen ihrer Dienstdefinitionen erstellen und mithilfe des Änderungsberaters die Auswirkungen der Änderungen auf ihre Tests und virtuellen Dienste verstehen, bevor sie Änderungen vornehmen. Sobald Änderungen vorgenommen wurden, können Sie mit Change Advisor vorhandene Assets schnell und problemlos aktualisieren, um die Änderungen innerhalb der Microservices widerzuspiegeln.

Testen reaktiver Mikrodienste

Eines der Hauptziele einer Microservices-Architektur ist die Erstellung unabhängiger Komponenten. Dadurch wird das Bereitstellen, Skalieren und Aktualisieren der Dienste einfacher. Dieses Ziel wird jedoch bei Verwendung des Orchestrierungsmusters nicht vollständig verwirklicht, da einzelne Mikrodienste direkte Abhängigkeiten von anderen Mikrodiensten aufweisen. Eine Möglichkeit, dies zu lösen, besteht darin, das Choreografiemuster zu verwenden, das auch als "reaktive" oder "ereignisgesteuerte" Mikrodienste bezeichnet wird. In diesem Muster verweisen Mikrodienste nicht direkt aufeinander. Stattdessen senden sie Nachrichten an Ereignisströme, die andere Microservices abonniert haben.

Siehe folgendes Beispiel:

Nehmen wir in diesem Beispiel an, der Portfolio-Service wurde angewiesen, eine Aktienposition hinzuzufügen. Anstatt den Kontodienst direkt aufzurufen, wird ein Ereignis im Ereignisstrom "Position hinzugefügt" veröffentlicht. Der Accounts-Mikroservice hat diesen Ereignisstrom abonniert, damit er die Benachrichtigung erhält. Es wird überprüft, ob der Benutzer über genügend Guthaben auf seinem Konto verfügt. In diesem Fall wird der Betrag auf dem Benutzerkonto reduziert und ein Ereignis im Ereignisstrom "Konto aktualisiert" veröffentlicht. Wenn der Benutzer nicht über genügend Guthaben auf seinem Konto verfügt, veröffentlicht er möglicherweise ein Fehlerereignis in einem anderen Ereignisstrom (zur Vereinfachung des Beispiels nicht dargestellt). Der Portfolio-Mikroservice hat den Ereignisstrom "Konto aktualisiert" abonniert. Wenn das vom Konten-Mikroservice veröffentlichte Ereignis angezeigt wird, aktualisiert er sein Portfolio basierend auf der Bestätigung durch den Kontodienst.

Die asynchrone Kommunikation in dieser Art von Architektur bietet den Vorteil, dass die Dienste stark voneinander entkoppelt sind - Instanzen jedes Dienstes können ersetzt, erneut bereitgestellt oder skaliert werden, ohne dass sich die anderen Mikrodienste darum kümmern. Der Nachteil ist, dass die asynchrone Natur der Ereignisse es schwieriger macht zu verstehen, wie das System ausgeführt wird und wie der Ereignisfluss aussehen wird. Abhängig von der Reihenfolge oder Art der Ereignisse, die erzeugt werden, kann sich das System auf unerwartete Weise verhalten. Dies ist als emergentes Verhalten bekannt und eine inhärente Herausforderung bei der Entwicklung und Erprobung choreografierter Mikrodienste.

Muster für asynchrone Befehlsaufrufe

Es gibt unterschiedliche asynchrone Nachrichtenmuster die unter die breitere Kategorie der ereignisgesteuerten Mikrodienste fallen. Das Muster für asynchrone Befehlsaufrufe wird verwendet, wenn Mikrodienste mithilfe asynchroner Aktionen orchestriert werden müssen. Dabei muss ein Mikrodienst einen anderen Mikrodienst asynchron aufrufen und gleichzeitig sicherstellen, dass der zweite Mikrodienst die Nachricht empfangen hat. In diesem Muster werden Nachrichten normalerweise mithilfe von Warteschlangen ausgetauscht.

Ein gängiges Framework, das in Microservice-Architekturen zur Implementierung dieses Musters verwendet wird, ist RabbitMQ. Eine bestimmte Inkarnation dieses Musters tritt auf, wenn ein Mikrodienst ein Ereignis veröffentlichen muss, damit ein zweiter Mikrodienst verarbeitet werden kann, und dann warten muss, bis ein "Antwort" -Ereignis von diesem zweiten Mikrodienst gelesen wird.

Betrachten Sie das gerade besprochene Portfolio-Beispiel, in dem ein REST-API-Aufruf den Portfolio-Mikroservice anweist, eine Position hinzuzufügen. Der Portfolio-Service stellt ein Ereignis in die Warteschlange "Position hinzugefügt", damit der Mikrodienst "Konten" verarbeitet werden kann, und wartet darauf, dass der Dienst "Konten" ein Antwortereignis in die Warteschlange "Konto aktualisiert" sendet, damit der REST-API-Aufruf die von diesem Ereignis empfangenen Daten zurückgeben kann. Es gibt zwei verschiedene Möglichkeiten, ein Testszenario für dieses Beispiel zu konfigurieren:

  1. Die erste Methode besteht darin, eine Umgebung mit den erforderlichen Warteschlangen zu erstellen, in der der Portfolio-Dienst bereitgestellt wird, der Kontodienst jedoch nicht. Da der Kontodienst nicht bereitgestellt wird, muss das Testszenario das Verhalten des Kontodienstes simulieren, indem das erwartete Ereignis zum entsprechenden Zeitpunkt vom Kontodienst gebucht wird. Ein Parasoft SOAtest-Testszenario wird mit zwei Tests erstellt: einem, der die REST-API des Portfolio-Service ausführt, und einem zweiten Test, der das Ereignis vom Accounts-Service aus veröffentlicht. Die Tests müssen so konfiguriert werden, dass sie gleichzeitig ausgeführt werden, damit das Ereignis vom Kontodienst veröffentlicht wird, während der Portfolio-Dienst auf das Ereignis wartet.
  2. Anstatt den Kontodienst mithilfe eines Tests zum Posten seines Ereignisses zu simulieren, kann es hilfreich sein, einen wiederverwendbaren virtuellen Dienst zu erstellen, der auf Ereignisse wartet, die in die Warteschlange "Position hinzugefügt" gepostet werden, und ein resultierendes Ereignis in die Warteschlange "Konto aktualisiert" sendet. Dieser virtuelle Mikroservice kann dann in mehreren verschiedenen Testszenarien wiederverwendet werden, die ihn möglicherweise benötigen.

Der erste Ansatz ist einfach und erstellt ein in sich geschlossenes Test-Asset, das keine zusätzlichen externen Abhängigkeiten von der Testinfrastruktur aufweist. Der zweite Ansatz ist wiederverwendbar und ist eine genauere Simulation des tatsächlichen Verhaltens des Systems. Der zweite Ansatz hat jedoch die Kosten für das Erstellen, Bereitstellen und Verwalten eines separaten virtuellen Assets.

Eine Variation des asynchronen Befehlsaufrufmusters ist ein Mikrodienst, der eine Warteschlange auf ein eingehendes Ereignis abhört, das Ereignis verarbeitet und dann ein Folgeereignis in einer anderen Warteschlange veröffentlicht, damit ein oder mehrere andere Mikrodienste verarbeitet werden können:

In diesem Beispiel ist der Microservice Invoice der Service, der getestet werden muss. Der Payments-Service veröffentlicht ein Ereignis in der RabbitMQ-Warteschlange „Payment Processed“, damit der Invoice-Service es abholen kann. Der Invoice-Microservice liest das Ereignis aus der Warteschlange, erstellt eine Rechnung und veröffentlicht dann ein Ereignis in der Invoice Created-Warteschlange, um den E-Mail-Microservice anzuweisen, eine E-Mail mit der Rechnung an den Kunden zu senden. Um ein Testszenario für den Invoice-Microservice zu erstellen, kann eine Testumgebung konfiguriert werden, die zwei RabbitMQ-Warteschlangen und den bereitgestellten Invoice-Microservice enthält. Es kann ein Parasoft-SOAtest-Testszenario erstellt werden, das ein Payment-Processed-Ereignis in der Payment Processed-Warteschlange veröffentlicht. Das Szenario abonniert dann die Warteschlange "Rechnung erstellt", um zu überprüfen, ob das richtige Ereignis "Rechnung erstellt" als Antwort vom Rechnungsdienst veröffentlicht wird. Dies ist ein sehr einfaches Testszenario, das den Rechnungsdienst isoliert testet.

Ereignis Firehose Muster

Das Ereignis-Firehose-Muster wird verwendet, wenn verschiedene Quellen eine sehr hohe Anzahl von Ereignissen erzeugen, die über einen gemeinsamen Hub schnell an verschiedene Verbraucher übermittelt werden müssen. In diesem Muster werden Nachrichten über Themen ausgetauscht (im Gegensatz zum Muster für asynchrone Befehlsaufrufe, bei dem die Nachrichten über Warteschlangen ausgetauscht werden). Ein allgemeines Framework, das zum Implementieren des Ereignis-Firehose-Musters verwendet wird, ist das Apache Kafka Framework, und es sieht ein bisschen so aus:

Angenommen, wir möchten einen einzelnen Microservice testen, der ein Kafka-Thema abonniert, die empfangenen Ereignisse verarbeitet und seine Ergebnisse dann in einem zweiten Kafka-Thema veröffentlicht. Zum Beispiel so etwas:

In diesem Beispiel haben wir einen Prognosemikroservice, der ein Wetterdatenthema abonniert, das viele verschiedene Wetterdaten aus vielen verschiedenen Quellen sammelt. Anschließend verarbeitet es diese Daten, um sein Prognosemodell zu aktualisieren, und veröffentlicht Prognosedaten im Thema Prognosedaten. In diesem Fall müssen wir überprüfen, ob der Prognosedienst die erwarteten Ereignisse für einen bestimmten Satz von Wetterdatenereignissen im Thema Prognosedaten veröffentlicht.

Dies würde durch Konfigurieren einer Testumgebung erfolgen, die die beiden Kafka-Themen und den bereitgestellten Prognosedienst enthält. Das Testszenario veröffentlicht zuerst die erforderlichen Ereignisse im Thema Wetterdaten und abonniert dann das Thema Prognosedaten, um zu überprüfen, ob die richtigen Prognosedatenereignisse vom Prognosedienst veröffentlicht wurden. Es müssten mehrere verschiedene Testszenarien erstellt werden, um die verschiedenen Arten und die Reihenfolge der Ereignisse zu überprüfen, von denen erwartet werden kann, dass sie vom Prognosemikroservice verarbeitet werden.

Dies ist ein relativ einfaches Testszenario. Die Tatsache, dass der Prognosemikroservice von den anderen Mikrodiensten entkoppelt ist, hat den glücklichen Nebeneffekt, dass der Test für den Prognosedienst auch von den Mikrodiensten entkoppelt ist. In diesem Fall müssen Sie keine komplexe Umgebung mit virtuellen Diensten einrichten. Sie können einfach nur Testszenarien erstellen, in denen Ereignisse veröffentlicht werden, und überprüfen, ob die richtigen Ereignisse als Antwort erstellt wurden.

Testumgebungen konfigurieren

Viele Microservice-Teams haben einen CI / CD-Prozess (Continuous Integration / Continuous Deployment) zum Erstellen, Testen und Bereitstellen von containerisierten Microservices eingeführt, um den Prozess zu automatisieren und die mit der Bereitstellung von Updates verbundenen Risiken zu verringern.

In diesem Prozess wird automatisch ein Container-Image erstellt und in einer Testumgebung bereitgestellt (häufig verwaltet von.), Die den Microservice enthält Kubernetes oder eine Kubernetes-basierte Distribution wie OpenShift), wo der Microservice validiert werden kann, bevor er in End-to-End-Tests und schließlich in die Produktion übertragen wird. Ich würde empfehlen zu lesen CI / CD für Containerized Microservices und Design von Microservices: Kontinuierliche Integration. Beide Artikel beschreiben diese Art von Prozess sehr gut.

Service-Virtualisierung zum Testen von Microservices

Einige der besprochenen Testmuster basieren auf der Verwendung virtueller Dienste für abhängige Microservices. Diese virtuellen Dienste müssen aus den gleichen Gründen, aus denen die von ihnen simulierten Microservices komponentenbasiert sind, hochgradig komponentenbasiert und leicht bereitzustellen sein. Damit die Dienstvirtualisierung in diesen Umgebungen funktioniert, müssen Sie containerisierte virtuelle Dienste erstellen, die einfach bereitgestellt werden können.

Um einen containerisierten virtuellen Dienst zu erstellen, können Sie ein Basisimage erstellen, das Parasoft Virtualize und alle seine Abhängigkeiten enthält, und es mit einem anderen Image überlagern, das die gesamte Konfiguration der virtuellen Assets für den virtuellen Dienst enthält. Das neue Image für den virtuellen Dienst kann zusammen mit dem Container für den zu testenden Mikrodienst und all seinen (virtualisierten) Abhängigkeiten als Container in der Docker / Kubernetes-Umgebung bereitgestellt werden.

Fazit

Wenn Teams Microservices einführen, ist es wichtig zu verstehen, wie sie ausreichend getestet werden. Die Messaging-Muster und die zugehörigen Testmuster, die ich hier besprochen habe, sind nicht neu, aber die Notwendigkeit, diese Muster zu verwenden, hat erheblich zugenommen, da Microservices immer häufiger werden und mehr Anwendungen ein Microservice-Paradigma übernehmen.

Zu Erstellen und Bereitstellen von Testszenarien für Ihre Microservices mit maximaler Flexibilitätkönnen Sie nutzen Parasoft SOAtest, Parasoft VirtualisierenUnd der Kontinuierliche Testplattform von Parasoft um die höchste Qualität und Zuverlässigkeit Ihrer Microservices zu gewährleisten.

So vereinfachen Sie das Testen von Microservices-Architekturen

Von Nathan Jakubiak

Nathan ist Entwicklungsdirektor bei Parasoft. Er und seine Teams entwickeln Produktfunktionen in den Bereichen UI-Tests (Selenic), API-Tests (SOAtest), Service-Virtualisierung (Virtualize) und Unit-Tests (Jtest). Er ist seit 2000 bei Parasoft.

Erhalten Sie die neuesten Nachrichten und Ressourcen zum Testen von Software sofort.