O que é um contrato de API e por que ele guia os testes
Um contrato de API é uma especificação formal do que a API aceita e do que ela devolve: endpoints, formatos de payload, tipos, campos obrigatórios, regras de validação e exemplos. Em testes, o contrato funciona como uma fonte de verdade verificável: você deriva casos de teste a partir dele e valida se o comportamento real está aderente ao que foi prometido.
Quando o contrato está em OpenAPI (Swagger), ele pode ser lido por humanos e também por ferramentas para validação automática, geração de mocks, geração de clientes e checagens de compatibilidade.
- Testes guiados por contrato: o contrato define o que testar (campos, tipos, regras, cenários de erro).
- Detecção de divergências: documentação diz uma coisa, implementação faz outra (ou vice-versa).
- Prevenção de breaking changes: mudanças que quebram consumidores podem ser detectadas comparando versões do contrato.
Como ler um documento OpenAPI: mapa mental da estrutura
Um documento OpenAPI (YAML/JSON) costuma ter estas seções principais:
openapi: versão da especificação (ex.:3.0.3,3.1.0).info: metadados (nome, versão do serviço).servers: URLs base.paths: endpoints e operações (GET/POST/PUT...).components: reutilização (schemas, parameters, responses, securitySchemes).
Paths e operations
Em paths, cada rota (ex.: /users/{id}) contém operações (ex.: get, put). Em cada operação, você encontra:
operationId: identificador único (útil para rastrear testes).parameters: parâmetros de path/query/header/cookie.requestBody: corpo da requisição (quando aplicável).responses: respostas por status code, com conteúdo e schema.tags,summary,description: documentação (não executável, mas útil para intenção).
Exemplo mínimo (trecho OpenAPI)
paths:
/users/{id}:
get:
operationId: getUser
parameters:
- name: id
in: path
required: true
schema:
type: integer
minimum: 1
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/User'
examples:
ok:
value:
id: 10
name: "Ana"
status: "ACTIVE"Parameters: como interpretar e transformar em validações
Cada item em parameters tem:
- Ouça o áudio com a tela desligada
- Ganhe Certificado após a conclusão
- + de 5000 cursos para você explorar!
Baixar o aplicativo
nameein(path/query/header/cookie).required: obrigatório ou não.schema: tipo e restrições.exampleouexamples: valores ilustrativos (podem virar casos de teste).
Restrições comuns em parameters
- Numéricas:
minimum,maximum,exclusiveMinimum,exclusiveMaximum,multipleOf. - Strings:
minLength,maxLength,pattern(regex),format(ex.:email,uuid,date-time). - Enum:
enum: [A, B, C]. - Arrays:
items,minItems,maxItems,uniqueItems.
Em testes, cada restrição vira pelo menos: um caso válido e um caso inválido (limites e formatos).
requestBody: conteúdo, schema e obrigatoriedade
requestBody descreve o corpo da requisição e normalmente inclui:
required: se o corpo é obrigatório.content: mapa por media type (ex.:application/json), contendoschemae exemplos.
Exemplo com required, enum e constraints
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [name, status]
properties:
name:
type: string
minLength: 2
maxLength: 60
status:
type: string
enum: [ACTIVE, INACTIVE]
email:
type: string
format: email
examples:
create:
value:
name: "Ana"
status: "ACTIVE"
email: "ana@exemplo.com"Note a diferença entre:
requestBody.required: exige a presença do corpo.schema.required: exige campos dentro do JSON.
responses: o que validar em cada status code
Em responses, cada status code define:
description: intenção.headers(opcional): headers específicos da resposta.content: por media type, comschemae exemplos.
Exemplo com múltiplas respostas
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/User'
'404':
description: Not Found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'Em testes de contrato, você valida que:
- Para um cenário de sucesso, o corpo atende ao schema do
200. - Para um cenário de recurso inexistente, o corpo atende ao schema do
404. - O tipo de cada campo e as regras (required, enum, min/max, pattern) são respeitados.
Schemas (components/schemas): tipos, required e composição
Os schemas definem a estrutura dos objetos. Em OpenAPI 3, você verá frequentemente:
type: objectcompropertieserequired.type: arraycomitems.$refpara reutilizar schemas.- Composição:
oneOf,anyOf,allOf(atenção: isso impacta muito os testes).
Exemplo de schema com constraints e required
components:
schemas:
User:
type: object
required: [id, name, status]
properties:
id:
type: integer
minimum: 1
name:
type: string
minLength: 2
status:
type: string
enum: [ACTIVE, INACTIVE]
tags:
type: array
items:
type: string
maxItems: 10
uniqueItems: trueExemplos (example/examples): como usar sem cair em armadilhas
example e examples ajudam a entender o payload esperado e podem ser usados para:
- Gerar rapidamente um caso “happy path”.
- Servir de base para mutações (alterar um campo por vez para criar casos inválidos).
Cuidados comuns:
- Exemplo pode estar desatualizado e não refletir o schema (ex.: campo faltando, enum inválido).
- Exemplo pode omitir campos opcionais importantes para cenários reais.
Enums e constraints: como derivar casos de teste sistematicamente
Enum
Para um campo com enum, derive:
- Um teste para cada valor permitido (ou amostragem representativa, se a lista for grande).
- Um teste com valor fora do enum (ex.:
"BLOCKED"quando só aceitaACTIVE/INACTIVE). - Um teste com tipo errado (ex.: número em vez de string), se o schema permitir detectar.
Min/Max e limites
Para minimum: 1 e maximum: 10:
- Válidos: 1, 10 e um valor intermediário (ex.: 5).
- Inválidos: 0 e 11.
- Se for
exclusiveMinimum, ajuste (ex.: mínimo exclusivo 1 → 1 é inválido, 2 é válido).
Pattern (regex)
Para pattern, crie:
- Um valor que casa com a regex (válido).
- Um valor que falha por pouco (inválido), para garantir que a validação não é “solta”.
code:
type: string
pattern: '^[A-Z]{3}-\d{4}$'
# Válido: "ABC-1234"
# Inválido: "abc-1234" (case), "AB-1234" (tamanho), "ABC-123" (dígitos)Required
Para required em objetos:
- Teste válido com todos os campos obrigatórios presentes.
- Teste inválido removendo um campo obrigatório por vez (para identificar mensagens e comportamento).
- Teste com campos extras (se a API aceita ou rejeita; em JSON Schema isso pode ser controlado por
additionalProperties).
Derivando casos de teste do contrato (passo a passo prático)
Passo 1 — Escolha uma operação e liste entradas e saídas
Para uma operação (ex.: POST /users):
- Entradas: parameters + requestBody (campos, tipos, required, constraints).
- Saídas: responses por status code (schema e constraints).
Passo 2 — Monte uma matriz de casos a partir das regras
Crie uma tabela de cobertura mínima por campo/regra:
| Elemento | Regra no contrato | Teste válido | Teste inválido |
|---|---|---|---|
| requestBody | required: true | Enviar body | Sem body |
| name | minLength 2 | "Ana" | "A" |
| status | enum | "ACTIVE" | "BLOCKED" |
| format email | "a@b.com" | "abc" |
Passo 3 — Gere variações por mutação controlada
Parta de um payload válido (geralmente do example) e altere um aspecto por vez:
- Remover campo obrigatório.
- Trocar tipo (string → number).
- Quebrar pattern.
- Estourar maxLength/maxItems.
- Enviar enum inválido.
Isso ajuda a isolar a causa quando o comportamento diverge do contrato.
Passo 4 — Valide compatibilidade de tipos e obrigatoriedade na resposta
Para cada resposta esperada:
- Valide que o corpo é compatível com o schema (tipos corretos, campos required presentes).
- Valide constraints (ex.:
id >= 1,statusdentro do enum). - Valide arrays e objetos aninhados (itens e required internos).
Passo 5 — Cubra cenários alternativos definidos por oneOf/anyOf
Se o schema usar oneOf (ex.: resposta pode ser um de dois formatos), derive testes para cada alternativa e garanta que a resposta se encaixa em apenas uma (quando aplicável).
Identificando divergências entre documentação e comportamento real
Durante a execução, divergências típicas aparecem como:
- Campo documentado como required, mas ausente na resposta real.
- Tipo diferente (ex.: contrato diz
integer, API retorna string"10"). - Enum “expandido” na prática (API retorna valor não documentado).
- Constraints não aplicadas (API aceita
namecom 1 caractere apesar deminLength: 2). - Schema desatualizado (campo novo aparece sem estar no contrato).
- Exemplos inconsistentes com o schema.
Como tratar:
- Se a implementação está correta e o contrato está errado: atualizar o OpenAPI e versionar.
- Se o contrato está correto e a implementação está errada: abrir bug e priorizar correção (pode ser breaking change para consumidores).
- Se há ambiguidade: ajustar o contrato para remover interpretações (ex.: definir
nullable,oneOf, required, exemplos).
Roteiro de validação automática de contrato
1) Validação estática do documento OpenAPI
- Rodar um validador/linter de OpenAPI para checar estrutura, referências quebradas (
$ref) e inconsistências. - Checar se exemplos respeitam os schemas (quando a ferramenta suportar).
2) Validação de requisição (client-side) baseada no contrato
- Antes de enviar, validar se o payload gerado pelos testes atende ao schema (útil para garantir que seus testes não estão enviando lixo sem querer).
- Gerar dados válidos automaticamente a partir do schema (quando possível) e aplicar mutações para negativos.
3) Validação de resposta (server-side behavior) baseada no contrato
- Após cada chamada, validar o corpo retornado contra o schema do status code correspondente.
- Validar headers documentados (quando existirem no contrato).
- Registrar divergências com evidência: operação, status code, caminho do campo (ex.:
$.status), valor recebido e regra violada.
4) Checagem de compatibilidade entre versões do contrato
- Comparar contrato atual vs anterior para detectar mudanças potencialmente quebradoras: remoção de campos, mudança de tipo, tornar campo obrigatório, remover valores de enum, alterar constraints para mais restritivas.
- Bloquear pipeline quando houver breaking change não aprovado.
5) Execução contínua em ambientes
- Executar validação de contrato em CI e também periodicamente em ambiente de homologação/staging para detectar drift (implementação mudou sem atualizar contrato).
Roteiro de validação manual (checklist prático)
Leitura dirigida do OpenAPI
- Escolha 1–2 operações críticas e leia:
parameters→requestBody→responses. - Liste campos required e constraints relevantes (min/max, pattern, enum).
- Verifique se há exemplos e se parecem realistas.
Execução manual com foco em aderência ao contrato
- Faça uma chamada com payload do exemplo e compare a resposta com o schema (campos, tipos, enum).
- Remova um required por vez e observe se a API rejeita como esperado.
- Teste limites (min/max) e padrões (pattern) com valores “quase válidos”.
- Verifique se a API retorna campos não documentados e se isso é aceitável para consumidores.
Registro de divergências
- Para cada divergência, anote: operação (
operationId), request enviada, response recebida, trecho do contrato e impacto (breaking ou não). - Classifique: erro de documentação vs erro de implementação vs ambiguidade do contrato.
Dicas de organização dos testes orientados a contrato
- Nomeie testes por
operationId+ regra (ex.:createUser_required_name). - Mantenha um conjunto de payloads válidos “base” por operação e aplique mutações pequenas para negativos.
- Priorize validações que mais quebram integrações: required, tipos, enums e formatos.
- Quando houver
$refcompartilhado, crie testes que exercitem o schema em diferentes operações para detectar inconsistências sistêmicas.