Sobes.tech
Middle+

Fale sobre os testes de contrato de um microserviço.

sobes.tech IA

Resposta da IA

Os testes de contrato concentram-se na verificação da interação entre microserviços ao nível da sua API (contrato). O objetivo é garantir que o consumidor (serviço que utiliza a API) e o fornecedor (serviço que fornece a API) cumpram um "contrato" definido (esquema de pedidos/respostas, formato de dados, expectativas).

Princípios básicos:

  • Consumidor-dirigido: Os testes baseiam-se nas expectativas do consumidor. O consumidor determina quais dados e formatos necessita.
  • Testes bidirecionais: Verifica-se tanto a capacidade do consumidor (para trabalhar com o contrato atual) como a do fornecedor (para cumprir as expectativas do consumidor).
  • Velocidade: Os testes são executados rapidamente, muitas vezes numa pipeline CI/CD, pois não requerem a implantação de todos os serviços dependentes.

O processo geralmente inclui:

  1. O consumidor cria testes que descrevem as suas expectativas para a API do fornecedor. Estes testes geram um "contrato".
  2. O contrato é publicado (por exemplo, num repositório centralizado).
  3. O fornecedor usa o contrato publicado para verificar a sua implementação da API. Executa testes (geralmente do lado do fornecedor), que verificam se a sua API cumpre o contrato.
  4. Em caso de discrepância entre as expectativas do consumidor e a implementação do fornecedor, o teste falha, indicando uma violação do contrato.

Ferramentas:

  • Pact (o mais popular)
  • Spring Cloud Contract
  • Swagger/OpenAPI com ferramentas de validação

Vantagens:

  • Detecção precoce de erros de integração: Os problemas de compatibilidade são detectados antes do deployment.
  • Redução da necessidade de testes de integração: Diminui a dependência de testes de ponta a ponta complexos e lentos.
  • Testes independentes: Permite testar os serviços de forma independente.
  • Definição clara de expectativas: Define explicitamente o contrato entre serviços.

Desvantagens:

  • Não substitui completamente os testes de integração (apenas verifica a interação ao nível da API).
  • Requer disciplina na gestão de versões dos contratos.
  • Pode ser mais complexo para serviços com contratos muito complexos.

Exemplo de uso com Pact:

  1. O consumidor (por exemplo, o serviço Order Service) usa a biblioteca Pact para criar testes do lado do consumidor.
    // Exemplo de teste do consumidor com 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 {
            // Lógica para chamar a API do fornecedor através de mockServer
            // Verifica que o consumidor manipula corretamente a resposta mockada
            HttpResponse response = Request.Get(mockServer.getUrl() + "/products/1").execute().returnResponse();
            assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
        }
    }
    
  2. Ao executar os testes do lado do consumidor, é gerado um arquivo de contrato (.json).
  3. Este arquivo de contrato é publicado no Pact Broker ou noutro repositório centralizado.
  4. O fornecedor (Product Service) usa a biblioteca Pact (por exemplo, Pact Provider Verifier) para verificar a sua implementação da API com base no contrato obtido do Pact Broker.
    // Exemplo de teste do fornecedor com Pact Provider Verifier
    @Provider("ProductService")
    @PactFolder("relative/path/to/pacts") // ou usar 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() {
            // Lógica para preparar o estado dos dados no serviço do fornecedor para o teste
        }
    
        // Adiciona a URL do provedor onde o serviço testado está em execução
        @BeforeEach
        void beforeEach(PactVerificationContext context) {
            context.setTarget(new HttpTestTarget("localhost", 8080));
        }
    }
    
  5. O verificador do lado do fornecedor chama a API real do fornecedor de acordo com a especificação do contrato e compara a resposta recebida com a esperada no contrato.

O teste de contrato é uma prática importante para garantir a fiabilidade e a manutenção de sistemas baseados em microserviços.