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
- Uso de Matchers de Tipo (
like,integer): Evita acoplamento a valores estáticos, validando que o provedor retorne os tipos de dados acordados. - Provider State (
given): Informa ao provedor qual estado inicial de banco de dados deve ser configurado antes do teste de validação. - 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
-
Slides da Aula
-
Quiz de Fixação
-
Exercícios Práticos
-
Desafio de Projeto