Pular para conteúdo

Aula 18 - Testes de Contrato de APIs e Schema-First 📜

Objetivo Pedagógico

Objetivo: Estruturar testes de contrato de APIs orientados a microsserviços usando o Pact Framework (Consumer-Driven Contracts), prevenindo quebras de integração sem a necessidade de manter ambientes integrados frágeis e pesados.


📑 1. Fundamentos Teóricos & Análise Técnica

Na arquitetura de microsserviços, a proliferação de serviços interdependentes torna os testes de ponta a ponta (E2E) excessivamente lentos, frágeis e difíceis de manter.

Os Testes de Contrato Dirigidos pelo Consumidor (Consumer-Driven Contract Testing - CDC) resolvem esse problema desacoplando a validação: 1. O Paradigma Consumer-Driven: - O Consumidor (Consumer) define formalmente quais endpoints consome e quais campos do payload e status de resposta são estritamente necessários para seu funcionamento. - Essa expectativa é serializada em um arquivo de contrato padronizado (o arquivo Pact JSON). 2. Validação Isolada do Provedor (Provider Verification): - O Provedor (Provider) não necessita que o consumidor esteja online para testar a integração. - O provedor lê o arquivo Pact publicado em um servidor central (Pact Broker) e simula as requisições contra sua própria API em ambiente de teste unitário/componente, atestando se sua implementação satisfaz o contrato prometido. 3. Prevenção de Quebras de Produção com can-i-deploy: - Antes de realizar o deploy de qualquer microsserviço em produção, a ferramenta consulta o Pact Broker via CLI (pact-broker can-i-deploy). - Se o provedor não tiver verificado positivamente a versão exata do contrato exigido pelo consumidor, o deploy é bloqueado no pipeline de CI.

📐 Arquitetura Conceitual & Diagrama de Fluxo

sequenceDiagram
    autonumber
    participant C as Consumidor (Frontend/App)
    participant B as Pact Broker (Repositório Central)
    participant P as Provedor (API Microsserviço)
    Note over C: Teste Unitário do Consumidor gera contrato Pact JSON
    C->>B: Publica Contrato (v1.2.0)
    Note over P: Provedor executa suite de testes de contrato
    P->>B: Baixa contratos vigentes dos consumidores
    P->>P: Executa replay das requisições contra API local
    P->>B: Publica resultado: Verificação APROVADA!
    Note over C,P: Ferramenta can-i-deploy libera o deploy em produção!

🔍 Pilares e Diretrizes Técnicas

Nesta unidade, aprofundamos os seguintes conceitos fundamentais: - Desacoplamento de Ambientes: Elimina a dependência de ambientes de teste integrados instáveis onde a queda de um serviço trava o teste de todos os demais. - Evolução Segura de APIs: Campos não utilizados pelos consumidores podem ser depreciados ou removidos sem receio de impactos em produção. - Pact Broker Matrix: Matriz multidimensional que valida a compatibilidade cruzada entre versões de consumidores e provedores em múltiplos ambientes (Dev, Staging, Prod). - Mocking Determinístico: O framework provê servidor mock local gerado a partir do contrato para testes unitários do consumidor.


🛠️ 2. Implementação Prática em Pact Framework e Testes de Contrato Dirigidos pelo Consumidor (CDC)

Abaixo está a implementação técnica de referência, estruturada com padrões de engenharia de software e foco em robustez:

// consumer_contract.test.js (Definição de Contrato Pact com Mock Service)
import { PactV3, MatchersV3 } from '@pact-foundation/pact';
import axios from 'axios';

const { like, string, integer } = MatchersV3;

const provider = new PactV3({
  consumer: 'WebFrontend',
  provider: 'OrderService',
});

describe('Contrato com OrderService', () => {
  it('deve retornar pedido detalhado com status 200', async () => {
    // 1. Definir expectativa do contrato
    provider
      .given('existe um pedido com ID 100')
      .uponReceiving('uma requisição para buscar o pedido 100')
      .withRequest({
        method: 'GET',
        path: '/orders/100',
        headers: { Accept: 'application/json' },
      })
      .willRespondWith({
        status: 200,
        headers: { 'Content-Type': 'application/json' },
        body: {
          id: integer(100),
          customerName: like('Carlos Silva'),
          status: string('PROCESSANDO'),
        },
      });

    // 2. Executar teste contra o Mock Server do Pact
    await provider.executeTest(async (mockserver) => {
      const response = await axios.get(`${mockserver.url}/orders/100`, {
        headers: { Accept: 'application/json' },
      });
      expect(response.status).toBe(200);
      expect(response.data.id).toBe(100);
    });
  });
});

💡 Análise Passo a Passo do Código

  1. Uso de Matchers de Tipo (like, integer): Evita acoplamento a valores estáticos, validando que o provedor retorne os tipos de dados acordados.
  2. Provider State (given): Informa ao provedor qual estado inicial de banco de dados deve ser configurado antes do teste de validação.
  3. Geração Automática do Pact JSON: A execução bem-sucedida do teste unitário serializa o contrato formal para upload no Pact Broker.

🎯 3. Próximos Passos & Sequência Didática