Middle+
Erzählen Sie von der Vertragsprüfung eines Microservices.
sobes.tech KI
Antwort von AI
Contract-Tests konzentrieren sich auf die Überprüfung der Interaktion zwischen Microservices auf API-Ebene (Vertrag). Ziel ist es sicherzustellen, dass Verbraucher (Service, der die API nutzt) und Anbieter (Service, der die API bereitstellt) einen "Vertrag" (Schema für Anfragen/Antworten, Datenformat, Erwartungen) einhalten.
Grundprinzipien:
- Verbraucher-gesteuert: Tests basieren auf den Erwartungen des Verbrauchers. Der Verbraucher bestimmt, welche Daten und Formate er benötigt.
- Zweiseitige Tests: Es wird sowohl geprüft, ob der Verbraucher (mit dem aktuellen Vertrag arbeiten kann) als auch, ob der Anbieter (die Erwartungen des Verbrauchers erfüllt) funktioniert.
- Schnelligkeit: Tests werden schnell ausgeführt, oft im Rahmen einer CI/CD-Pipeline, da sie keine vollständige Bereitstellung aller abhängigen Dienste erfordern.
Der Prozess umfasst in der Regel:
- Der Verbraucher erstellt Tests, die seine Erwartungen an die API des Anbieters beschreiben. Diese Tests generieren einen "Vertrag".
- Der Vertrag wird veröffentlicht (z.B. in einem zentralen Repository).
- Der Anbieter nutzt den veröffentlichten Vertrag, um seine API-Implementierung zu verifizieren. Er führt Tests aus (meist auf der Seite des Anbieters), die prüfen, ob seine API dem Vertrag entspricht.
- Bei Abweichungen zwischen den Erwartungen des Verbrauchers und der Implementierung des Anbieters schlägt der Test fehl und weist auf eine Vertragsverletzung hin.
Werkzeuge:
- Pact (am beliebtesten)
- Spring Cloud Contract
- Swagger/OpenAPI mit Validierungstools
Vorteile:
- Frühe Fehlererkennung bei Integration: Kompatibilitätsprobleme werden bereits vor der Bereitstellung erkannt.
- Reduzierung der Notwendigkeit von Integrationstests: Verringert die Abhängigkeit von komplexen und langsamen End-to-End-Tests.
- Unabhängige Tests: Ermöglicht das Testen von Diensten unabhängig voneinander.
- Klare Definition der Erwartungen: Legt explizit den Vertrag zwischen Diensten fest.
Nachteile:
- Ersetzt keine vollständigen Integrationstests (prüft nur die Interaktion auf API-Ebene).
- Erfordert Disziplin bei der Versionierung der Verträge.
- Kann bei sehr komplexen Verträgen für Dienste schwieriger sein.
Beispiel mit Pact:
- Der Verbraucher (z.B. der Dienst
Order Service) verwendet die Pact-Bibliothek, um Consumer-Tests zu erstellen.// Beispiel für einen Verbraucher-Test mit Pact JVM @ExtendWith(PactConsumerTestExt.class) @PactTestFor(providerName = "ProductService", port = "8080") public class ProductServiceContractTest { @Pact(consumer = "OrderService") public RequestResponsePact createPact(PactDslWithRequest r) { return r.given("a product with id 1 exists") .uponReceiving("a request for product by id") .path("/products/1") .method("GET") .willRespondWith() .status(200) .headers(Map.of("Content-Type", "application/json")) .body(new PactDslJsonBody() .stringValue("id", "1") .stringValue("name", "Laptop") .numberType("price", 1200.00)) .toPact(); } @Test void testGetProductById(MockServer mockServer) throws IOException { // Logik zum Aufrufen der API des Anbieters über mockServer // Überprüfung, ob der Verbraucher die Mock-Antwort korrekt verarbeitet HttpResponse response = Request.Get(mockServer.getUrl() + "/products/1").execute().returnResponse(); assertThat(response.getStatusLine().getStatusCode(), equalTo(200)); } } - Bei der Ausführung der Verbraucher-Tests wird eine Vertragsdatei (
.json) generiert. - Diese Vertragsdatei wird in einem Pact Broker oder einem anderen zentralen Repository veröffentlicht.
- Der Anbieter (
Product Service) nutzt die Pact-Bibliothek (z.B. Pact Provider Verifier), um seine API-Implementierung anhand des aus dem Pact Broker erhaltenen Vertrags zu verifizieren.// Beispiel für einen Anbieter-Test mit Pact Provider Verifier @Provider("ProductService") @PactFolder("relative/path/to/pacts") // oder Pact Broker verwenden public class ProductServiceVerificationTest { @TestTemplate @ExtendWith(PactVerificationInvocationContextProvider.class) public void verifyPact(PactVerificationContext context) { context.verifyInteraction(); } @State("a product with id 1 exists") public void productWithId1Exists() { // Logik zur Vorbereitung des Datenzustands im Anbieter-Service für den Test } // URL des Anbieters, auf dem der zu testende Service läuft @BeforeEach void beforeEach(PactVerificationContext context) { context.setTarget(new HttpTestTarget("localhost", 8080)); } } - Der Verifier auf der Anbieterseite ruft die reale API des Anbieters entsprechend der Vertragsspezifikation auf und vergleicht die erhaltene Antwort mit der im Vertrag erwarteten.
Vertragstests sind eine wichtige Praxis, um die Zuverlässigkeit und Wartbarkeit von auf Microservices basierenden Systemen sicherzustellen.