Testes de Contrato no Node.js verificam se dois sistemas concordam sobre formato, campos, status, eventos e regras de compatibilidade. Eles são especialmente úteis entre APIs, consumidores, filas e microserviços desenvolvidos por equipes diferentes.
Um teste unitário pode confirmar que o cliente monta uma requisição. Um teste do provedor pode confirmar que a rota responde. O teste de contrato conecta essas expectativas e detecta mudanças incompatíveis antes do deploy.
Neste guia, você aprenderá contratos HTTP e assíncronos, OpenAPI, JSON Schema, consumer-driven contracts, versionamento e CI.
O que é um contrato?
Um contrato define elementos observáveis:
- método e caminho;
- headers obrigatórios;
- schema de request;
- status e schema de resposta;
- códigos de erro;
- campos opcionais;
- formato de eventos;
- regras de compatibilidade.
Contrato HTTP simples
GET /users/{id}
200
{
"id": "string",
"email": "string",
"active": true
}O teste deve validar estrutura e comportamento relevante, sem fixar campos que não pertencem ao contrato.
OpenAPI
Uma especificação OpenAPI pode ser a fonte do contrato. Veja OpenAPI no Node.js.
O pipeline pode validar a especificação, gerar clientes e comparar mudanças incompatíveis.
JSON Schema
Use JSON Schema para requests, respostas e eventos. Consulte JSON Schema no Node.js.
const schema = {
type: 'object',
required: ['id', 'email'],
properties: {
id: { type: 'string' },
email: { type: 'string', format: 'email' },
active: { type: 'boolean' }
},
additionalProperties: false
};Validação de resposta
const response = await fetch(`${baseUrl}/users/123`);
assert.equal(response.status, 200);
const body = await response.json();
assert.equal(validate(body), true, JSON.stringify(validate.errors));Consumer-driven contracts
Nesse modelo, o consumidor registra as interações que realmente utiliza. O provedor verifica se continua atendendo essas expectativas.
Isso reduz contratos gigantes baseados em possibilidades teóricas, mas exige governança para não aceitar expectativas contraditórias.
Estado do provedor
O contrato pode exigir um cenário específico, como “usuário 123 existe”. O provedor deve preparar esse estado de forma determinística antes do teste.
Não teste implementação
O contrato deve observar a fronteira. Não inclua nomes de tabelas, funções internas ou ordem de queries.
Campos opcionais
Consumidores precisam distinguir campo ausente, nulo e vazio. Documente semântica e teste as variações aceitas.
Compatibilidade aditiva
Adicionar campo opcional geralmente é compatível quando consumidores ignoram propriedades desconhecidas. Consumidores que rejeitam qualquer campo extra tornam evolução mais difícil.
Mudanças incompatíveis
- remover campo obrigatório;
- trocar tipo;
- renomear status ou código;
- alterar unidade;
- mudar enum sem fallback;
- tornar campo opcional obrigatório;
- modificar semântica sem mudar schema.
Erros também são contrato
{
"code": "USER_NOT_FOUND",
"message": "Usuário não encontrado"
}Clientes devem depender de códigos estáveis, não de mensagens humanas.
Autenticação
Teste ausência de credencial, escopo insuficiente e token válido. Não desative segurança para executar contratos.
Eventos assíncronos
Contratos de fila precisam definir:
- nome e versão do evento;
- schema;
- chave de idempotência;
- timestamp;
- ordenação esperada;
- política para campos extras;
- tratamento de evento inválido.
Versionando eventos
Prefira evolução compatível e consumidores tolerantes. Quando a semântica muda profundamente, publique nova versão do evento e mantenha transição.
Contratos e testes de integração
Testes de contrato validam acordo. Testes de integração validam funcionamento com infraestrutura real. Use os dois. Veja Testes de Integração no Node.js.
Ambientes
Não use produção como primeira verificação. Contratos devem rodar em CI com servidor efêmero e dados controlados.
Publicação de contratos
Armazene versões do contrato em repositório ou broker controlado. Registre consumidor, provedor, versão do código e resultado da verificação.
Can I deploy?
Antes do deploy, a automação pode verificar se a nova versão do provedor satisfaz contratos dos consumidores ativos e se o novo consumidor é compatível com provedores disponíveis.
Branch e ambientes temporários
Contratos de branches devem expirar ou ser associados a versões reais. Caso contrário, expectativas antigas bloqueiam releases sem necessidade.
Mocks gerados pelo contrato
Um mock server ajuda o consumidor, mas não prova que o provedor real corresponde. Sempre execute verificação no provedor.
CI recomendado
- validar schema;
- executar testes do consumidor;
- publicar contrato;
- executar verificação do provedor;
- comparar breaking changes;
- bloquear deploy incompatível.
Erros comuns
- contrato amplo demais;
- fixar campos irrelevantes;
- ignorar erros;
- não preparar estado;
- usar mock sem verificar provedor;
- tratar schema como semântica completa;
- não versionar eventos;
- não remover contratos obsoletos.
Checklist
- fronteira definida;
- schemas versionados;
- erros incluídos;
- autenticação testada;
- estado determinístico;
- consumidor e provedor verificados;
- breaking changes detectadas;
- deploy bloqueado quando incompatível.
Conclusão
Testes de Contrato no Node.js transformam integração entre equipes em uma regra verificável. Eles reduzem a dependência de ambientes compartilhados e detectam incompatibilidades antes da produção.
Mantenha contratos focados no que o consumidor realmente usa, valide o provedor real e trate erros e eventos como parte da API. Contratos pequenos e versionados facilitam evolução contínua.
Consulte a especificação OpenAPI e a especificação JSON Schema.




