Sobes.tech
Middle+

Ispričajte o testiranju ugovora mikroservisa.

sobes.tech АИ

Одговор од АИ

Контрактно тестирање се фокусира на проверу интеракције између микросервиса на нивоу њиховог API (контракт). Циљ је да се уверимо да потрошач (сервис који користи API) и добављач (сервис који пружа API) поштују одређени "контракт" (шема захтева/одговора, формат података, очекивања).

Основни принципи:

  • Потрошач-води: Тестови се заснивају на очекивањима потрошача. Потрошач одређује које податке и формате му требају.
  • Двосмерно тестирање: Проверја се како страна потрошача (да ли може да ради са тренутним контрактом), тако и страна добављача (да ли његова реализација одговара очекивањима потрошача).
  • Брзина: Тестови се брзо извршавају, често у оквиру CI/CD конвејера, јер не захтевају распоређивање свих зависних сервиса.

Процес обично укључује:

  1. Потрошач креира тестове који описују његова очекивања од API-ја добављача. Ови тестови генеришу "контракт".
  2. Контракт се објављује (нпр. у централизованом репозиторијуму).
  3. Добављач користи објављени контракт за верификацију своје реализације API-ја. Он покреће тестове (обично на страни добављача), који проверавају да ли његов API одговара контракту.
  4. У случају неслагања између очекивања потрошача и реализације добављача, тест пада, указујући на кршење контракта.

Алатке:

  • Pact (најпопуларнији)
  • Spring Cloud Contract
  • Swagger/OpenAPI са алатима за валидацију

Предности:

  • Рано откривање грешака у интеграцији: Проблеми са компатибилношћу се откривају још пре распоређивања.
  • Смањење потребе за интеграционим тестовима: Смањује зависност од сложених и спорих свеобухватних тестова.
  • Независно тестирање: Омогућава тестирање сервиса независно један од другог.
  • Јасно дефинисање очекивања: Јасно дефинише контракт између сервиса.

Недостаци:

  • Не замењује потпуно интеграционе тестове (само проверава интеракцију на нивоу API).
  • Захтева дисциплину у верзионисању контраката.
  • Може бити сложеније за сервисе са веома сложеним контрактима.

Пример коришћења са Pact:

  1. Потрошач (нпр. сервис Order Service) користи библиотеку Pact за креирање тестова на страни потрошача.
    // Пример теста потрошача са 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 добављача преко mockServer
            // Провера да ли потрошач правилно обрађује мок-одговор
            HttpResponse response = Request.Get(mockServer.getUrl() + "/products/1").execute().returnResponse();
            assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
        }
    }
    
  2. При извршавању тестова потрошача се генерише фајл контракта (.json).
  3. Овај фајл се објављује у Pact Broker или другом централизованом репозиторијуму.
  4. Добављач (Product Service) користи библиотеку Pact (нпр. Pact Provider Verifier) за верификацију своје реализације API на основу контракта добијеног из Pact Broker.
    // Пример теста добављача са Pact Provider Verifier
    @Provider("ProductService")
    @PactFolder("relative/path/to/pacts") // или коришћење 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() {
            // Логика припреме стања података у сервису добављача за тест
        }
    
        // Додајте URL добављача, где је покренута тестирана услуга
        @BeforeEach
        void beforeEach(PactVerificationContext context) {
            context.setTarget(new HttpTestTarget("localhost", 8080));
        }
    }
    
  5. Верификатор са стране добављача позива стварни API добављача у складу са спецификацијом контракта и пореди добијени одговор са очекиваним у контракту.

Контрактно тестирање је важна пракса за обезбеђивање поузданости и одрживости система базираних на микросервисима.