Sobes.tech
Middle+

Papaskinkite apie mikroserviso sutarties testavimą.

sobes.tech AI

Atsakymas iš AI

Sutartinis testavimas sutelkiamas į sąveikos tarp mikroservisų patikrinimą jų API (sutarčių) lygiu. Tikslas – įsitikinti, kad vartotojas (paslauga, naudojanti API) ir tiekėjas (paslauga, teikianti API) laikosi tam tikros "sutarties" (užklausų/atsakymų schemos, duomenų formato, lūkesčių).

Pagrindiniai principai:

  • Vartotojo-vedimas: Testai grindžiami vartotojo lūkesčiais. Vartotojas nustato, kokius duomenis ir formatus jam reikia.
  • Dvipusis testavimas: Patikrinama tiek vartotojo pusė (ar jis gali dirbti su dabartine sutartimi), tiek tiekėjo pusė (ar jo įgyvendinimas atitinka vartotojo lūkesčius).
  • Greitis: Testai vykdomi greitai, dažnai CI/CD vamzdyje, nes nereikia diegti visų priklausomų paslaugų.

Procesas dažnai apima:

  1. Vartotojas kuria testus, apibūdinančius savo lūkesčius dėl tiekėjo API. Šie testai generuoja "sutartį".
  2. Sutartis skelbiama (pavyzdžiui, centralizuotame saugykloje).
  3. Tiekėjas naudoja paskelbtą sutartį API įgyvendinimui patikrinti. Jis paleidžia testus (dažniausiai tiekėjo pusėje), kurie patikrina, ar jo API atitinka sutartį.
  4. Jei yra neatitikimų tarp vartotojo lūkesčių ir tiekėjo įgyvendinimo, testas žlunga, nurodydamas sutarties pažeidimą.

Įrankiai:

  • Pact (populiariausias)
  • Spring Cloud Contract
  • Swagger/OpenAPI su validacijos įrankiais

Privalumai:

  • Ankstyvas klaidų aptikimas integracijoje: Problemos su suderinamumu nustatomos dar prieš diegimą.
  • Sumažina integracinių testų poreikį: Sumažina priklausomybę nuo sudėtingų ir lėtų galutinių testų.
  • Nepriklausomas testavimas: Leidžia testuoti paslaugas nepriklausomai viena nuo kitos.
  • Aiškus lūkesčių apibrėžimas: Aiškiai nustato sutartį tarp paslaugų.

Trūkumai:

  • Nenuima visiškai integracinių testų (tik tikrina sąveiką API lygiu).
  • Reikalauja disciplinos versijų valdyme.
  • Gali būti sudėtingesnis labai sudėtingų sutarčių paslaugoms atveju.

Pavyzdys naudojant Pact:

  1. Vartotojas (pavyzdžiui, Order Service) naudoja Pact biblioteką kurti vartotojo pusės testus.
    // Vartotojo testas su 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 {
            // API kvietimo logika per mockServer
            // Patikrinama, ar vartotojas tinkamai apdoroja mock atsakymą
            HttpResponse response = Request.Get(mockServer.getUrl() + "/products/1").execute().returnResponse();
            assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
        }
    }
    
  2. Vykdant vartotojo pusės testus, generuojamas sutarties failas (.json).
  3. Šis sutarties failas skelbiamas Pact Broker ar kitame centralizuotame saugykloje.
  4. Tiekėjas (Product Service) naudoja Pact biblioteką (pavyzdžiui, Pact Provider Verifier) API įgyvendinimo patikrinimui remiantis gauta sutartimi.
    // Tiekėjo testas su Pact Provider Verifier
    @Provider("ProductService")
    @PactFolder("relative/path/to/pacts") // arba naudoti 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() {
            // Paruošimo logika tiekėjo duomenų būsenai testui
        }
    
        // Pridedame tiekėjo URL, kur veikia testuojama paslauga
        @BeforeEach
        void beforeEach(PactVerificationContext context) {
            context.setTarget(new HttpTestTarget("localhost", 8080));
        }
    }
    
  5. Tiekėjo verifieris iškviečia tikrą tiekėjo API pagal sutarties specifikaciją ir lygina gautą atsakymą su laukiamu sutartyje.

Sutartinis testavimas yra svarbi praktika užtikrinant patikimumą ir palaikomumą mikroservice pagrindu sukurtose sistemose.