Sicherstellung der Kompatibilität von Microservices mit verbrauchergesteuerten Verträgen
Min-jun Kim
Dev Intern · Leapcell

Der stille Killer von Integrationsproblemen bei Microservices
In der dynamischen Landschaft der modernen Softwareentwicklung hat sich die Microservices-Architektur als dominantes Paradigma etabliert, das unübertroffene Skalierbarkeit, Flexibilität und unabhängige Bereitstellbarkeit bietet. Diese verteilte Natur bringt jedoch auch eine erhebliche Herausforderung mit sich: Wie stellen wir sicher, dass unabhängig entwickelte und bereitgestellte Dienste nahtlos und ohne unerwartete Integrationsfehler kommunizieren können? Traditionelles Integrationstesting entwickelt sich oft zu einem komplexen und zeitaufwendigen Unterfangen, das aufwendige Testumgebungen und eine enge Koordination zwischen den Teams erfordert. Wenn eine breaking change in einem Backend-Dienst auftritt, erkennen Client-Anwendungen oder nachgelagerte Dienste dies möglicherweise erst zur Laufzeit, was zu Produktionsvorfällen und frustrierten Benutzern führt.
Dieses Problem unterstreicht den kritischen Bedarf an einem effizienteren und zuverlässigeren Ansatz für das Integrationstesting in einem Microservices-Ökosystem. Hier kommen "Consumer-Driven Contract Testing" (verbrauchergesteuertes Vertrags-Testing) mit Tools wie Pact.io ins Spiel und bieten eine pragmatische Lösung zur Gewährleistung der Kompatibilität und Förderung der unabhängigen Entwicklung. Dieser Artikel befasst sich mit den Prinzipien und der praktischen Anwendung von verbrauchergesteuertem Vertrags-Testing mit Pact.io und zeigt, wie es Teams in die Lage versetzt, resiliente und gut integrierte Microservices zu entwickeln.
Verständnis der Säulen des Vertrags-Testings mit Pact
Bevor wir uns intensiv mit der Implementierung befassen, wollen wir ein gemeinsames Verständnis der Kernkonzepte entwickeln, die dem verbrauchergesteuerten Vertrags-Testing und Pact.io zugrunde liegen.
- Microservice: Ein unabhängig bereitstellbarer, kleiner und lose gekoppelter Dienst, der sich auf eine spezifische Geschäftsfähigkeit konzentriert.
 - Consumer: Ein Dienst oder eine Anwendung, die Anfragen an einen anderen Dienst stellt. Zum Beispiel kann ein 
Order Serviceein Consumer einesProduct Servicesein, wenn er Produktdetails benötigt. - Provider: Ein Dienst, der auf Anfragen eines anderen Dienstes antwortet. Im vorherigen Beispiel ist der 
Product Serviceder Provider für denOrder Service. - Contract: Eine formelle Vereinbarung zwischen einem Consumer und einem Provider, die das erwartete Format von Anfragen und Antworten festlegt. Dieser Vertrag spezifiziert die Interaktionen, die der Consumer vom Provider erwartet.
 - Consumer-Driven Contract (CDC) Testing: Eine Entwicklungspraxis, bei der der Consumer den Vertrag definiert. Der Consumer schreibt Tests, die die Daten spezifizieren, die er vom Provider erwartet und die er an den Provider sendet. Diese "Consumer-Verträge" werden dann verwendet, um zu überprüfen, ob der Provider diese Erwartungen erfüllt.
 - Pact.io: Ein Open-Source-Framework für verbrauchergesteuertes Vertrags-Testing. Es ermöglicht Consumern, ihre Erwartungen an die API eines Providers so zu definieren, dass sie gegen die tatsächliche Implementierung des Providers überprüft werden können.
 
Das Prinzip hinter verbrauchergesteuerten Verträgen
Das Grundprinzip des CDC-Testings ist eine Verlagerung der Verantwortung für die Definition der Integrationspunkte. Anstatt dass der Provider die API vorgibt (was dazu führen kann, dass Consumern brechen, wenn der Provider seine API unerwartet ändert), gibt der Consumer explizit an, was er vom Provider benötigt und erwartet. Diese Definition wird zum Vertrag.
Pact.io erleichtert dies, indem es dem Consumer ermöglicht:
- Erwartungen definieren: Der Consumer-Dienst schreibt einen "Pact-Test", in dem er die genauen HTTP-Anfragen spezifiziert, die er an den Provider senden wird, und die genauen HTTP-Antworten, die er zu empfangen erwartet. Dies umfasst die Anfrage-Methode, den Pfad, die Header, den Body und den erwarteten Antwort-Status, die Header und den Body.
 - Pact-Datei generieren: Während der Ausführung der Tests des Consumers zeichnet Pact.io diese definierten Erwartungen in eine "Pact-Datei" (ein JSON-Dokument) auf. Diese Datei repräsentiert den Vertrag.
 - Pact-Datei veröffentlichen: Der Consumer veröffentlicht diese Pact-Datei dann in einem "Pact Broker" (ein zentrales Repository für Verträge) oder teilt sie direkt mit dem Provider-Team.
 - Provider verifizieren: Der Provider-Dienst verwendet dann diese Pact-Datei zusammen mit seiner eigenen API-Implementierung zur Verifizierung. Pact.io führt "Provider-Verifizierungstests" aus, die die im Vertrag definierten Anfragen gegen den tatsächlichen Provider-Dienst abspielen. Wenn die Antworten des Providers mit den Erwartungen in der Pact-Datei übereinstimmen, wird der Vertrag erfüllt. Bei einer Nichtübereinstimmung schlagen die Provider-Verifizierungstests fehl, was auf eine breaking change hinweist.
 
Ein praktisches Beispiel: Order Service und Product Service
Betrachten wir ein gängiges Szenario: Ein Order Service, der Produktdetails von einem Product Service abrufen muss, um eine Bestellung zu erfüllen.
Consumer-Seite (Order Service)
Der Order Service muss ein Produkt anhand seiner ID abrufen. Hier ist ein vereinfachtes Beispiel in Java mit Spring Boot und der Pact JVM-Bibliothek.
// OrderServiceConsumerPactTest.java import au.com.dius.pact.consumer.MockServer; import au.com.dius.pact.consumer.dsl.PactDslWith

