Parâmetros, paginação e ordenação em testes de API: garantindo previsibilidade

Capítulo 5

Tempo estimado de leitura: 10 minutos

+ Exercício

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 aceito

2) 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: limit máximo, offset não-negativo, pageSize dentro 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

CategoriaExemplosO que validar na resposta
Tipo inválidolimit=abc, page=-1Status de erro consistente, mensagem/código de erro, campo apontado
Fora do limitelimit=1000 (max 100), offset=-10Rejeição ou clamp (se contrato permitir), nunca comportamento silencioso inesperado
Formato inválidofrom=01-31-2025 quando exige ISOErro com detalhe do formato esperado
Enum inválidostatus=UNKNOWNErro ou lista vazia (defina contrato); preferível erro para entrada inválida
Defaultsem sort, sem limitOrdenação e tamanho padrão aplicados e estáveis
Parâmetro repetidostatus=PAID&status=SHIPPEDRegra clara: última ocorrência, união, ou erro

Passo a passo: como desenhar testes de parâmetros

  1. Liste os parâmetros do endpoint (path/query/body) e marque: tipo, obrigatório, default, limites, formato.
  2. Crie um conjunto mínimo de dados de teste com variedade (datas diferentes, valores iguais em campos de ordenação, múltiplos status).
  3. Escreva testes positivos (valores válidos) e valide: status, schema, e regras de negócio (ex.: filtro realmente filtra).
  4. Escreva testes negativos para cada regra: tipo inválido, fora do limite, formato inválido, enum inválido, campo obrigatório ausente.
  5. Verifique defaults: faça a mesma requisição com e sem o parâmetro e compare o comportamento esperado (ex.: limit default, sort default).
  6. 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.

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

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=40

Pontos 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=20

Pontos de atenção em testes:

  • page mínimo (0 ou 1) e comportamento para page=0 quando 1-based.
  • pageSize máximo e default.
  • Metadados: total, totalPages, page, pageSize coerentes.

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: nextCursor ausente 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

  1. Escolha uma ordenação estável (ex.: sort=createdAt,id).
  2. Busque páginas sequenciais até esgotar (ou até N páginas para smoke).
  3. Extraia o identificador único de cada item (ex.: id).
  4. Asserções:
    • Nenhum id repetido entre páginas.
    • Quantidade total coletada = total (se o contrato fornecer total e 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).
# 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=createdAt aplica a ordem correta.
  • Direção: asc/desc (ex.: sort=-createdAt ou direction=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 desc

Filtros: 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=PAID retorna apenas itens com status PAID.
  • Filtro por lista: status=PAID,SHIPPED ou parâmetros repetidos.
  • Intervalo: createdAtFrom/createdAtTo com 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

  1. Escolha um filtro que retorne um conjunto conhecido (ex.: 37 itens).
  2. Solicite pageSize=20 e valide: página 1 com 20 itens, página 2 com 17 itens.
  3. Valide que todos os itens em ambas as páginas respeitam o filtro.
  4. 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/01

Respostas 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: total pode ser 0; hasNext false; nextCursor ausente/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.lengthpaging.limit.
  • Se offsettotal, então items é vazio e hasNext=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ão items é 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 nextCursor estiver 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 retorna items: [].
  • 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.

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

Ao testar uma API com paginação, qual prática ajuda a evitar duplicação/omissão de itens entre páginas e reduz flutuações nos testes?

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

Você errou! Tente novamente.

Uma ordenação determinística com tie-breaker mantém a sequência estável entre requisições, evitando que itens “saltem” de página e reduzindo duplicação/omissão em testes de paginação.

Próximo capitúlo

Códigos de status HTTP em testes de API: critérios de sucesso e falha

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

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.