Modelagem de casos de teste para APIs: cenários positivos, negativos e limites

Capítulo 14

Tempo estimado de leitura: 10 minutos

+ Exercício

O que significa “modelar” casos de teste para APIs

Modelar casos de teste é transformar requisitos (contrato, regras de negócio e expectativas de consumo) em um conjunto de cenários verificáveis, cobrindo: positivos (uso correto), negativos (uso incorreto/hostil) e limites (bordas onde falhas são comuns). O objetivo não é “testar tudo”, e sim criar uma suíte pequena, mas representativa, que maximize a chance de detectar defeitos com o menor número de testes.

Uma forma prática de pensar é separar cada endpoint em três camadas de variação:

  • Entrada: body, query/path params, headers relevantes, contexto de autenticação/escopo.
  • Processamento: regras (validações, cálculos, transições de estado, consistência entre recursos).
  • Saída: status, payload, headers de resposta, efeitos colaterais (criação/alteração de dados).

Técnicas para derivar casos a partir de entradas e saídas

1) Particionamento de equivalência (PE)

Particionamento de equivalência divide o domínio de entrada em classes onde o sistema tende a se comportar de forma semelhante. Em vez de testar todos os valores, você escolhe representantes de cada classe.

Exemplo (campo age em um cadastro):

  • Classe válida: age entre 18 e 120 (inclusive).
  • Classe inválida (abaixo): age < 18.
  • Classe inválida (acima): age > 120.
  • Classe inválida (tipo): string, null, boolean.

Casos mínimos derivados por PE: 1 valor de cada classe (ex.: 25, 17, 121, “vinte”, null).

Continue em nosso aplicativo e ...
  • Ouça o áudio com a tela desligada
  • Ganhe Certificado após a conclusão
  • + de 5000 cursos para você explorar!
ou continue lendo abaixo...
Download App

Baixar o aplicativo

2) Análise de valores limite (VL)

Valores limite focam nas bordas das regras, onde erros de comparação (< vs <=) e arredondamentos são frequentes. Para cada faixa, teste: limite inferior, logo abaixo, logo acima e limite superior.

Exemplo (mesma regra 18..120):

  • 17 (abaixo), 18 (limite), 19 (acima)
  • 119 (abaixo), 120 (limite), 121 (acima)

Para strings, limites comuns: minLength, maxLength, vazio, e “max+1”. Para listas/paginação: 0, 1, limite máximo, máximo+1.

3) Tabelas de decisão

Tabelas de decisão ajudam quando o resultado depende de combinações de condições. Você lista condições (entradas/contexto) e ações/saídas esperadas, e então escolhe um conjunto de regras representativas.

Exemplo (criação de pedido com cupom):

RegraUsuário ativoCupom existeCupom expiradoValor mínimo atingidoResultado
R1SimSimNãoSimAplicar desconto
R2SimSimSimSimRejeitar cupom
R3SimNão--Rejeitar cupom
R4NãoSimNãoSimRejeitar (usuário inválido)
R5SimSimNãoNãoRejeitar (mínimo não atingido)

Em vez de testar todas as combinações possíveis, você cobre as regras que representam comportamentos distintos.

4) Transições de estado

Transições de estado modelam recursos que mudam de “fase” (ex.: pedido, assinatura, ticket). O foco é validar: transições permitidas, transições proibidas, e efeitos (campos alterados, timestamps, eventos).

Exemplo (pedido): DRAFT -> CONFIRMED -> PAID -> SHIPPED -> DELIVERED e cancelamento permitido até PAID (por exemplo).

  • Positivo: CONFIRMED -> PAID retorna sucesso e atualiza status.
  • Negativo: tentar SHIPPED -> PAID deve falhar.
  • Limite: ações repetidas (ex.: pagar duas vezes) e concorrência (duas requisições de pagamento simultâneas) devem manter consistência.

Passo a passo prático para modelar casos por endpoint

Passo 1: Liste entradas e saídas observáveis

  • Entradas: campos do body, query/path params, headers relevantes ao comportamento, contexto de permissão/escopo.
  • Saídas: status, corpo, headers de resposta, e efeitos persistidos (consultáveis via GET).

Passo 2: Identifique regras e invariantes

Invariantes são verdades que devem se manter em qualquer cenário válido. Exemplos típicos:

  • Campos obrigatórios sempre presentes em respostas de sucesso.
  • IDs retornados são únicos e podem ser consultados.
  • Operações de atualização não removem campos não relacionados.
  • Listagens respeitam paginação e ordenação solicitadas.

Passo 3: Aplique PE e VL aos campos críticos

Priorize campos com maior risco: dinheiro, datas, identificadores, enums de status, limites de paginação, campos usados em filtros, e qualquer campo com validação complexa.

Passo 4: Use tabela de decisão para combinações de regras

Quando houver múltiplas condições influenciando o resultado, modele com tabela e selecione regras representativas (incluindo as que causam falha).

Passo 5: Modele estados (quando houver ciclo de vida)

Desenhe o grafo de estados e derive casos para: transições válidas, inválidas, repetição, e tentativas fora de ordem.

Passo 6: Defina oráculos de teste (o que validar)

Para cada caso, defina verificações objetivas:

  • Status esperado.
  • Campos do payload (presença, tipo, valores, coerência).
  • Efeitos: consultar depois e comparar (ex.: GET após POST/PUT/PATCH/DELETE).
  • Não regressão: mudanças não devem afetar endpoints relacionados (consistência).

Como combinar parâmetros, headers e autenticação sem explosão combinatória

APIs reais têm muitas dimensões de variação: parâmetros, formatos, headers, perfis de usuário, escopos, e estados do recurso. Testar o produto cartesiano completo é inviável. Em vez disso, combine técnicas de seleção baseada em risco com cobertura por pares (pairwise) e testes direcionados para interações críticas.

Estratégia 1: Separe “o que muda o comportamento” do que é “ruído”

  • Alta influência: parâmetros que alteram regra de negócio, filtros, ordenação, paginação, flags, modo de cálculo, escopo/role.
  • Baixa influência: headers que não alteram lógica (ex.: alguns de rastreio), campos opcionais que não afetam processamento.

Teste exaustivo apenas para alta influência; para o resto, amostre.

Estratégia 2: Matriz mínima por dimensão (baseline + variações)

Crie um caso baseline (requisição válida e comum) e varie uma dimensão por vez para isolar falhas. Depois, adicione poucos testes de interação (2 ou 3) onde há risco conhecido.

Exemplo de dimensões em um GET de listagem:

  • Paginação: page, pageSize
  • Ordenação: sort
  • Filtro: status, createdFrom/To
  • Autorização: usuário comum vs admin

Você pode ter: 1 baseline + 1 variação por dimensão + 2 interações críticas (ex.: filtro+ordenação, paginação+ordenação).

Estratégia 3: Pairwise (cobertura por pares) para combinações

Quando há muitas opções por dimensão, use pairwise para garantir que cada par de valores entre dimensões apareça ao menos uma vez. Isso reduz drasticamente o número de testes e ainda captura muitos bugs de integração entre parâmetros.

Quando usar: múltiplos filtros e flags com histórico de bugs, ou endpoints muito usados.

Estratégia 4: Seleção baseada em risco (critérios objetivos)

Para decidir quais combinações entram na suíte, pontue cada variação por:

  • Impacto: financeiro, segurança, compliance, dados sensíveis.
  • Probabilidade: complexidade da regra, mudanças recentes, incidentes anteriores.
  • Exposição: volume de tráfego, clientes críticos, automação existente.

Inclua sempre: caminhos críticos, bordas, e falhas comuns (tipos inválidos, valores fora de faixa, estados inválidos).

Exemplos de suítes modeladas (com cenários positivos, negativos e limites)

Suíte 1: CRUD de um recurso (ex.: /users)

Objetivo: validar ciclo básico e consistência entre operações.

CategoriaCasoValidações principais
PositivoPOST cria usuário válidoResposta contém id; GET por id retorna os mesmos dados persistidos
PositivoPUT/PATCH atualiza campo permitidoSomente campos alterados mudam; demais permanecem
PositivoDELETE remove usuárioGET após delete não encontra; listagem não inclui
NegativoGET por id inexistenteErro padronizado; não vaza detalhes internos
NegativoAtualizar com payload inválidoErros por campo; nada é persistido
LimiteRepetir DELETEComportamento consistente (idempotência observável conforme regra do sistema)

Passo a passo sugerido para automatizar:

  • Crie um usuário (POST) e capture o id.
  • Consulte (GET) e compare campos relevantes.
  • Atualize (PATCH/PUT) e valide persistência via novo GET.
  • Delete e valide ausência via GET e via listagem.

Suíte 2: Validação de campos (PE + VL)

Objetivo: cobrir regras de validação com poucos casos bem escolhidos.

Exemplo (payload simplificado):

{ "name": "...", "email": "...", "age": 0, "document": "..." }
CampoPartições (exemplos)Valores limite (exemplos)
nameválido; vazio; muito longo; tipo inválidominLength, minLength-1, maxLength, maxLength+1
emailválido; sem @; domínio inválido; nulltamanho máximo; caracteres especiais
ageválido; abaixo; acima; tipo inválido17/18/19 e 119/120/121
documentválido; formato inválido; dígito verificador erradotamanho exato; tamanho-1; tamanho+1

Dica de modelagem: combine 1 erro por vez para diagnóstico rápido e adicione poucos casos com múltiplos erros apenas para validar agregação de mensagens.

Suíte 3: Paginação (limites e consistência)

Objetivo: garantir previsibilidade em listagens e evitar bugs de borda.

  • Positivo: primeira página com tamanho padrão retorna lista e metadados coerentes (ex.: total, page, pageSize, next/prev quando aplicável).
  • Limite: pageSize=1 e pageSize=max (permitido) retornam quantidades corretas.
  • Negativo: page=0, pageSize=0, pageSize=max+1 devem falhar de forma consistente.
  • Consistência: navegar páginas não deve repetir/omitir itens quando a ordenação é estável e o dataset não muda durante o teste.

Passo a passo:

  • Crie massa mínima (ex.: 25 itens) para tornar a paginação observável.
  • Liste com pageSize=10 e valide contagem por página.
  • Valide que a união dos IDs das páginas 1..3 tem 25 itens únicos.
  • Teste limites de pageSize e entradas inválidas.

Suíte 4: Erros padronizados (consistência entre cenários)

Objetivo: garantir que diferentes endpoints e diferentes tipos de falha retornem o mesmo “shape” de erro e campos mínimos para rastreio.

Modele uma lista de falhas representativas e aplique em múltiplos endpoints:

  • Payload inválido (campo obrigatório ausente).
  • Tipo inválido (string onde era número).
  • Recurso inexistente.
  • Conflito de negócio (duplicidade, estado inválido).

Validações:

  • Estrutura do erro é consistente (mesmos campos, tipos, e presença de identificador de correlação quando aplicável).
  • Mensagens por campo aparecem onde faz sentido (validação) e não aparecem onde não faz (ex.: inexistente).
  • Não há vazamento de stack trace, SQL ou detalhes internos.

Suíte 5: Consistência entre endpoints (invariantes do domínio)

Objetivo: detectar inconsistências quando diferentes endpoints representam o mesmo dado.

Exemplos de invariantes:

  • Após criar um recurso em POST /users, ele deve aparecer em GET /users (respeitando filtros) e em GET /users/{id}.
  • Se GET /orders/{id} retorna status=PAID, então GET /orders?status=PAID deve incluir esse pedido (quando filtros equivalentes são aplicados).
  • Se um endpoint retorna um resumo (ex.: /users) e outro retorna detalhe (ex.: /users/{id}), campos comuns devem ter valores coerentes.

Passo a passo para um teste de consistência típico:

  • Crie/atualize um recurso para um estado conhecido.
  • Consulte por múltiplos endpoints (detalhe, lista, busca por filtro).
  • Compare campos-chave (id, status, timestamps relevantes, relacionamentos).

Modelos prontos (templates) de casos para acelerar a derivação

Template de caso positivo

  • Dado: pré-condições (ex.: recurso existe, usuário com permissão X).
  • Quando: requisição com payload/params válidos (baseline).
  • Então: valida status, schema mínimo, e efeito persistido (GET de verificação).

Template de caso negativo

  • Dado: pré-condição válida (para isolar a falha na entrada).
  • Quando: 1 variação inválida (tipo, formato, fora de faixa, estado proibido).
  • Então: valida erro consistente e ausência de efeito colateral (não persistiu).

Template de caso de limite

  • Dado: dataset/estado preparado para tornar o limite observável.
  • Quando: valores na borda (min, min-1, max, max+1) ou transição no limiar.
  • Então: valida comportamento correto e estabilidade (sem flutuações inesperadas).

Agora responda o exercício sobre o conteúdo:

Ao modelar casos de teste para um endpoint com muitas dimensões (parâmetros, headers e autenticação), qual abordagem ajuda a evitar a explosão combinatória mantendo boa chance de encontrar defeitos?

Você acertou! Parabéns, agora siga para a próxima página

Você errou! Tente novamente.

Para evitar o produto cartesiano, recomenda-se partir de um baseline, variar uma dimensão por vez e incluir poucas interações de alto risco. Pairwise e seleção baseada em risco reduzem o número de testes sem perder cobertura relevante.

Próximo capitúlo

Evidências e observabilidade para testes de API: logs, correlação e diagnósticos

Arrow Right Icon
Capa do Ebook gratuito Testes de API: Conceitos Essenciais (REST, HTTP, Status Codes e Contratos)
93%

Testes de API: Conceitos Essenciais (REST, HTTP, Status Codes e Contratos)

Novo curso

15 páginas

Baixe o app para ganhar Certificação grátis e ouvir os cursos em background, mesmo com a tela desligada.