Por que parâmetros, paginação e ordenação precisam ser previsíveis em testes
Parâmetros (de caminho, query e corpo) controlam quais dados a API retorna e como ela os organiza. Em testes de API, “previsibilidade” significa que, para a mesma entrada, a API deve responder de forma consistente: mesmos critérios de filtro, mesma ordenação, mesmas regras de paginação e respostas claras quando a entrada é inválida. Isso reduz flutuações (flaky tests), evita bugs de duplicação/omissão entre páginas e garante que consumidores consigam navegar e compor resultados com segurança.
Tipos de parâmetros e o que testar
1) Parâmetros de caminho (path params)
São parte da rota e normalmente identificam um recurso (ex.: /users/{userId}). Em testes, foque em validações de formato, tipo e existência.
- Tipo e formato: inteiro, UUID, slug, etc.
- Limites: valores mínimos/máximos (ex.: id > 0).
- Caracteres inválidos: espaços, barras, caracteres fora do padrão.
- Existência: id bem-formado porém inexistente deve retornar resposta consistente (ex.: 404).
# Exemplo de casos para /users/{userId}
GET /users/123 # válido
GET /users/0 # limite inferior
GET /users/-1 # inválido
GET /users/abc # tipo inválido
GET /users/9999999999 # grande demais (se houver limite)
GET /users/550e8400-e29b-41d4-a716-446655440000 # se UUID for aceito2) Parâmetros de query (query params)
Controlam paginação, ordenação e filtros (ex.: ?status=active&sort=-createdAt&limit=20). Teste:
- Tipos: números, booleanos, enums, datas.
- Limites:
limitmáximo,offsetnão-negativo,pageSizedentro do range. - Formatos: datas ISO-8601, listas separadas por vírgula, intervalos.
- Valores padrão: quando omitidos, a API deve aplicar defaults documentados.
- Parâmetros desconhecidos: ignorar vs rejeitar (defina contrato e teste).
3) Parâmetros no corpo (body)
Comuns em buscas avançadas (ex.: POST /orders/search) ou filtros complexos. Teste:
- Tipos e coerção: string vs number, boolean, arrays.
- Campos obrigatórios vs opcionais: ausência, nulos, vazios.
- Limites: tamanho de string, tamanho de lista, ranges numéricos.
- Formato: datas, regex (ex.: e-mail), objetos aninhados.
- Defaults: quando um campo opcional não é enviado, o comportamento deve ser determinístico.
# Exemplo de body para busca
POST /orders/search
{
"filters": {
"status": ["PAID", "SHIPPED"],
"createdAt": {"from": "2025-01-01", "to": "2025-01-31"}
},
"sort": [{"field": "createdAt", "direction": "desc"}],
"page": {"pageSize": 20, "cursor": null}
}Validações essenciais: tipos, limites, formatos e defaults
Matriz de testes recomendada
| Categoria | Exemplos | O que validar na resposta |
|---|---|---|
| Tipo inválido | limit=abc, page=-1 | Status de erro consistente, mensagem/código de erro, campo apontado |
| Fora do limite | limit=1000 (max 100), offset=-10 | Rejeição ou clamp (se contrato permitir), nunca comportamento silencioso inesperado |
| Formato inválido | from=01-31-2025 quando exige ISO | Erro com detalhe do formato esperado |
| Enum inválido | status=UNKNOWN | Erro ou lista vazia (defina contrato); preferível erro para entrada inválida |
| Default | sem sort, sem limit | Ordenação e tamanho padrão aplicados e estáveis |
| Parâmetro repetido | status=PAID&status=SHIPPED | Regra clara: última ocorrência, união, ou erro |
Passo a passo: como desenhar testes de parâmetros
- Liste os parâmetros do endpoint (path/query/body) e marque: tipo, obrigatório, default, limites, formato.
- Crie um conjunto mínimo de dados de teste com variedade (datas diferentes, valores iguais em campos de ordenação, múltiplos status).
- Escreva testes positivos (valores válidos) e valide: status, schema, e regras de negócio (ex.: filtro realmente filtra).
- Escreva testes negativos para cada regra: tipo inválido, fora do limite, formato inválido, enum inválido, campo obrigatório ausente.
- Verifique defaults: faça a mesma requisição com e sem o parâmetro e compare o comportamento esperado (ex.:
limitdefault,sortdefault). - Teste combinações (filtro + ordenação + paginação) para garantir que a API aplica tudo de forma consistente.
Paginação: modelos e como testar
Paginação é uma “interface de navegação” do conjunto de resultados. Um contrato de paginação bem testado garante: tamanho de página, navegação correta, consistência entre páginas e comportamento previsível quando não há resultados.
- Ouça o áudio com a tela desligada
- Ganhe Certificado após a conclusão
- + de 5000 cursos para você explorar!
Baixar o aplicativo
Modelo A: limit/offset
Comum em listagens: ?limit=20&offset=40.
GET /orders?limit=20&offset=0
GET /orders?limit=20&offset=20
GET /orders?limit=20&offset=40Pontos de atenção em testes:
- Offset não-negativo e limit dentro do máximo.
- Consistência entre páginas: união das páginas deve corresponder ao conjunto esperado, sem duplicação/omissão (assumindo dados estáveis durante o teste).
- Última página: pode retornar menos itens que o limit.
- Offset além do total: deve retornar lista vazia (e metadados coerentes).
Modelo B: page/pageSize
Ex.: ?page=1&pageSize=20. Defina claramente se page é 0-based ou 1-based e teste isso.
GET /products?page=1&pageSize=20
GET /products?page=2&pageSize=20Pontos de atenção em testes:
- page mínimo (0 ou 1) e comportamento para
page=0quando 1-based. - pageSize máximo e default.
- Metadados:
total,totalPages,page,pageSizecoerentes.
Modelo C: cursor-based
Recomendado para listas grandes e dados mutáveis. Ex.: ?limit=20&cursor=eyJpZCI6... ou ?after=....
GET /events?limit=20
# resposta inclui nextCursor
GET /events?limit=20&cursor=<nextCursor>Pontos de atenção em testes:
- Cursor opaco: o cliente não deve depender do formato interno; teste apenas presença/ausência e uso.
- Estabilidade: navegar com cursor não deve repetir itens.
- Fim da lista:
nextCursorausente ou nulo quando não há próxima página. - Cursor inválido: erro consistente (ex.: 400) ou reinício controlado (se contrato permitir).
Testes de consistência entre páginas (sem duplicação/omissão)
Pré-condições para evitar flutuação
- Use um dataset controlado (ambiente de teste com dados fixos) ou congele a janela de dados com um filtro (ex.:
createdAt<=T). - Garanta uma ordenação determinística (ver seção de ordenação). Sem isso, a paginação pode “embaralhar” itens entre páginas.
Passo a passo: verificação de duplicação/omissão
- Escolha uma ordenação estável (ex.:
sort=createdAt,id). - Busque páginas sequenciais até esgotar (ou até N páginas para smoke).
- Extraia o identificador único de cada item (ex.:
id). - Asserções:
- Nenhum
idrepetido entre páginas. - Quantidade total coletada =
total(se o contrato fornecertotale o dataset for estável). - Quando a última página for alcançada, a próxima requisição deve retornar vazio e/ou indicar fim (dependendo do modelo).
- Nenhum
# Pseudológica de asserção (independente de linguagem)
ids = []
page = 1
while true:
resp = GET /items?page=page&pageSize=20&sort=createdAt,id
assert resp.status == 200
currentIds = map(resp.items, item => item.id)
assert intersection(ids, currentIds) is empty
ids.addAll(currentIds)
if resp.items.length < 20: break
page++
# opcional: assert ids.length == resp.total (se total for confiável e estável)Ordenação: estabilidade, critérios e testes
Ordenação determinística (estável) e tie-breaker
Se muitos itens têm o mesmo valor no campo ordenado (ex.: mesmo createdAt), a API precisa de um critério secundário (tie-breaker) para manter a ordem estável entre páginas. Um padrão é ordenar por createdAt desc, id desc (ou asc), garantindo que a sequência não mude entre requisições.
O que testar em ordenação
- Campo válido:
sort=createdAtaplica a ordem correta. - Direção: asc/desc (ex.:
sort=-createdAtoudirection=desc). - Múltiplos campos:
sort=createdAt,id. - Campo inválido: rejeitar com erro claro (preferível) ou ignorar (se contrato definir).
- Estabilidade entre páginas: com tie-breaker, itens não “pulam” de página.
# Exemplo de validação de ordenação
GET /items?limit=50&sort=createdAt,id
# Asserção: para todo i, (createdAt[i], id[i]) >= (createdAt[i+1], id[i+1]) em ordem descFiltros: combinando com paginação e ordenação
Filtros reduzem o conjunto antes da paginação. Testes devem garantir que a API filtra primeiro e pagina depois (e não o contrário).
Casos práticos para filtros
- Filtro por igualdade:
status=PAIDretorna apenas itens com status PAID. - Filtro por lista:
status=PAID,SHIPPEDou parâmetros repetidos. - Intervalo:
createdAtFrom/createdAtTocom datas ISO. - Busca textual:
q=term(teste normalização: case-insensitive, trimming, caracteres especiais conforme contrato). - Combinação:
status=PAID&createdAtFrom=...&sort=-createdAt,id.
Passo a passo: teste de filtro + paginação
- Escolha um filtro que retorne um conjunto conhecido (ex.: 37 itens).
- Solicite
pageSize=20e valide: página 1 com 20 itens, página 2 com 17 itens. - Valide que todos os itens em ambas as páginas respeitam o filtro.
- Valide que a ordenação é consistente em todas as páginas.
Comportamento com parâmetros inválidos e respostas vazias
Parâmetros inválidos: critérios objetivos
Defina e teste um padrão de erro para entradas inválidas. Exemplos de critérios objetivos:
- Para tipo/formato inválido: retornar erro (ex.: 400) com indicação do parâmetro e motivo.
- Para limites excedidos: erro (ex.: 400) indicando o limite permitido.
- Para combinação inválida: erro (ex.: ordenar por campo não permitido com determinado filtro), com mensagem clara.
# Exemplos de entradas inválidas
GET /items?limit=-1
GET /items?offset=-10
GET /items?page=0&pageSize=20 # se page for 1-based
GET /items?sort=unknownField
GET /items?createdAtFrom=2025/01/01Respostas vazias: o que validar
Respostas vazias são um resultado válido quando filtros não encontram dados ou quando a paginação ultrapassa o fim. Teste:
- Lista vazia com estrutura consistente (ex.:
items: []). - Metadados coerentes:
totalpode ser 0;hasNextfalse;nextCursorausente/nulo. - Status permanece sucesso (ex.: 200) para “nenhum resultado”, não erro.
Exemplos de contratos de paginação (para usar como base de testes)
Contrato 1: limit/offset com metadados
# Request
GET /orders?limit=20&offset=40&sort=-createdAt,id&status=PAID
# Response 200
{
"items": [
{"id": "o_120", "createdAt": "2025-01-20T10:00:00Z", "status": "PAID"}
],
"paging": {
"limit": 20,
"offset": 40,
"total": 57,
"hasNext": false
}
}Critérios objetivos de aceitação (exemplos):
paging.limit= valor solicitado ou default quando omitido.items.length≤paging.limit.- Se
offset≥total, entãoitemsé vazio ehasNext=false. - Ordenação aplicada: para todo par consecutivo,
(createdAt,id)está em ordem desc.
Contrato 2: page/pageSize com totalPages
# Request
GET /products?page=2&pageSize=10&sort=name,id
# Response 200
{
"items": [
{"id": "p_011", "name": "Cable"}
],
"paging": {
"page": 2,
"pageSize": 10,
"total": 35,
"totalPages": 4
}
}Critérios objetivos de aceitação (exemplos):
totalPages=ceil(total / pageSize).- Se
page > totalPages, entãoitemsé vazio (ou erro, se contrato definir; escolha um e teste). - Campos de paginação retornam os valores efetivos (após defaults/clamps, se existirem).
Contrato 3: cursor-based com nextCursor
# Request
GET /events?limit=3&sort=-createdAt,id
# Response 200
{
"items": [
{"id": "e_9", "createdAt": "2025-01-03T10:00:00Z"},
{"id": "e_8", "createdAt": "2025-01-03T09:00:00Z"},
{"id": "e_7", "createdAt": "2025-01-03T08:00:00Z"}
],
"paging": {
"limit": 3,
"nextCursor": "eyJsYXN0SWQiOiJlXzciLCJsYXN0Q3JlYXRlZEF0IjoiMjAyNS0wMS0wM1QwODowMDowMFoifQ=="
}
}Critérios objetivos de aceitação (exemplos):
- Se
nextCursorestiver presente, uma requisição com esse cursor retorna a próxima janela sem repetir itens. - Quando não houver mais itens,
nextCursoré nulo/ausente e a próxima página retornaitems: []. - Cursor inválido retorna erro consistente apontando o parâmetro
cursor.
Checklist de aceitação para previsibilidade (para transformar em testes)
- Defaults: omitir parâmetros resulta em comportamento documentado e estável (limit, sort, pageSize).
- Validação: tipos, formatos e limites inválidos geram erro consistente e detalhado.
- Ordenação: determinística com tie-breaker; mesma requisição retorna mesma ordem em execuções repetidas (com dataset estável).
- Paginação: sem duplicação/omissão ao percorrer páginas; última página e além do fim retornam vazio de forma consistente.
- Filtros: aplicados antes da paginação; todos os itens retornados respeitam os filtros.
- Combinações: filtro + sort + paginação funcionam juntos sem efeitos colaterais inesperados.