Sobes.tech
Middle+

Porozprávajte o kontraktovom testovaní mikroservisu.

sobes.tech AI

Odpoveď od AI

Kontraktné testovanie sa zameriava na overovanie interakcie medzi mikroslužbami na úrovni ich API (zmluva). Cieľom je zabezpečiť, že spotrebiteľ (služba, ktorá používa API) a poskytovateľ (služba, ktorá poskytuje API) dodržiavajú určitú "zmluvu" (schéma požiadavky/odpovede, formát dát, očakávania).

Hlavné princípy:

  • Spotrebiteľ-vedený: Testy sú založené na očakávaniach spotrebiteľa. Spotrebiteľ určuje, aké dáta a formáty potrebuje.
  • Obojstranné testovanie: Overuje sa, či strana spotrebiteľa (vie pracovať s aktuálnou zmluvou), aj strana poskytovateľa (zodpovedá jeho implementácia očakávaniam spotrebiteľa).
  • Rýchlosť: Testy sa vykonávajú rýchlo, často v rámci CI/CD pipeline, pretože nevyžadujú nasadenie všetkých závislých služieb.

Proces zvyčajne zahŕňa:

  1. Spotrebiteľ vytvorí testy, ktoré opisujú jeho očakávania od API poskytovateľa. Tieto testy generujú "zmluvu".
  2. Zmluva sa publikuje (napríklad v centralizovanom úložisku).
  3. Poskytovateľ používa publikovanú zmluvu na overenie svojej implementácie API. Spúšťa testy (zvyčajne na strane poskytovateľa), ktoré overujú, či jeho API zodpovedá zmluve.
  4. V prípade rozporu medzi očakávaniami spotrebiteľa a implementáciou poskytovateľa, test zlyhá, čo indikuje porušenie zmluvy.

Nástroje:

  • Pact (najpopulárnejší)
  • Spring Cloud Contract
  • Swagger/OpenAPI s nástrojmi na validáciu

Výhody:

  • Rané odhalenie chýb pri integrácii: Problémy s kompatibilitou sa odhaľujú ešte pred nasadením.
  • Zníženie potreby integračných testov: Znižuje závislosť od zložitých a pomalých end-to-end testov.
  • Nezávislé testovanie: Umožňuje testovať služby nezávisle od seba.
  • Jasné stanovenie očakávaní: Jasne definuje zmluvu medzi službami.

Nevýhody:

  • Nezastupuje úplne integračné testy (len kontroluje interakciu na úrovni API).
  • Vyžaduje disciplínu pri verzovaní zmlúv.
  • Môže byť zložitejšie pre služby s veľmi zložitými zmluvami.

Príklad použitia s Pact:

  1. Spotrebiteľ (napríklad, služba Order Service) používa knižnicu Pact na vytváranie testov na strane spotrebiteľa.
    // Príklad testu spotrebiteľa s 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 {
            // Logika volania API poskytovateľa cez mockServer
            // Kontrola, že spotrebiteľ správne spracováva mock-odpoveď
            HttpResponse response = Request.Get(mockServer.getUrl() + "/products/1").execute().returnResponse();
            assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
        }
    }
    
  2. Pri vykonávaní testov spotrebiteľa sa generuje súbor zmluvy (.json).
  3. Tento súbor sa publikuje do Pact Broker alebo iného centralizovaného úložiska.
  4. Poskytovateľ (Product Service) používa knižnicu Pact (napríklad Pact Provider Verifier) na overenie svojej implementácie API na základe zmluvy získanej z Pact Broker.
    // Príklad testu poskytovateľa s Pact Provider Verifier
    @Provider("ProductService")
    @PactFolder("relative/path/to/pacts") // alebo použitie Pact Broker
    public class ProductServiceVerificationTest {
    
        @TestTemplate
        @ExtendWith(PactVerificationInvocationContextProvider.class)
        public void verifyPact(PactVerificationContext context) {
            context.verifyInteraction();
        }
    
        @State("a product with id 1 exists")
        public void productWithId1Exists() {
            // Logika prípravy stavu dát v službe poskytovateľa pre test
        }
    
        // Pridať URL poskytovateľa, kde je spustená testovaná služba
        @BeforeEach
        void beforeEach(PactVerificationContext context) {
            context.setTarget(new HttpTestTarget("localhost", 8080));
        }
    }
    
  5. Verifier na strane poskytovateľa volá skutočné API poskytovateľa podľa špecifikácie zmluvy a porovnáva získanú odpoveď s očakávanou v zmluve.

Kontraktné testovanie je dôležitou praxou na zabezpečenie spoľahlivosti a udržateľnosti systémov založených na mikroslužbách.