Paginação, filtragem e ordenação

Defeitos comuns em APIs de listagem e como testar paginação, filtros e ordenação de forma completa.

Atualizado:

Sumário

APIs de listagem parecem simples, mas contêm muitos defeitos problemáticos. Verificar apenas se uma lista abre pode deixar passar registros duplicados ou ausentes, ordenação instável, totais incorretos, filtros quebrados e inconsistências entre páginas.

Listas aparecem em quase todo lugar: usuários, pedidos, pagamentos, logs, eventos, produtos, tarefas e comentários. Paginação, filtragem ou ordenação inadequadas fazem o produto parecer caótico: registros desaparecem ou aparecem duas vezes, filtros se comportam de forma inesperada, a ordem muda e a próxima página apresenta dados inconsistentes.

Por que APIs precisam desses recursos

Um servidor pode retornar todos os registros quando há poucos. Conforme os dados crescem, as respostas ficam pesadas, a renderização se torna difícil para o cliente e o backend consome recursos desnecessários.

  • →A paginação retorna os dados em partes
  • →A filtragem retorna o subconjunto necessário
  • →A ordenação define a ordem dos itens

Esses mecanismos quase sempre trabalham juntos. Um usuário abre uma lista de pedidos, filtra por status, ordena por data e navega entre páginas. A instabilidade em qualquer camada prejudica toda a experiência.

Paginação

A paginação divide um conjunto grande de dados em páginas ou lotes.

  • →Paginação por offset: page=2, limit=20 ou offset=20&limit=20
  • →Paginação por cursor: cursor=..., starting_after=..., next_page_token=...

QA precisa entender a diferença.

A paginação por offset é fácil de ler e comum em interfaces administrativas e APIs CRUD convencionais. Sua fraqueza é que o conteúdo das páginas pode se deslocar quando os dados mudam entre requisições. Um usuário vê 20 registros na primeira página; alguém adiciona um registro; a segunda página passa a conter duplicatas ou a pular registros.

A paginação por cursor geralmente é mais resistente a mudanças nos dados. É adequada para listas grandes e frequentemente atualizadas, feeds de eventos, transações e sistemas de alta carga. O teste visual é mais difícil porque QA precisa acompanhar um cursor e a ordem dos itens, em vez de um número de página familiar.

A principal implicação para QA é testar a paginação com dados em mudança, além de um conjunto estático.

Filtragem

A filtragem restringe um conjunto de dados de acordo com condições.

  • →status = active
  • →created_at >= data
  • →price entre X e Y
  • →owner_id = usuário atual
  • →Pesquisa por nome ou e-mail
  • →Vários filtros aplicados juntos

Esse recurso útil também é uma fonte frequente de defeitos lógicos.

  • →Um filtro é parcialmente ignorado
  • →Dois filtros se comportam de forma diferente quando usados juntos e separadamente
  • →Um filtro vazio e um filtro omitido recebem tratamentos diferentes
  • →A diferenciação entre maiúsculas e minúsculas é inesperada
  • →A filtragem por data falha devido aos fusos horários
  • →A filtragem do backend difere do que a interface espera
  • →Permissões ocultam alguns registros, levando o usuário a pensar que o filtro está quebrado

Testar a filtragem vai além de verificar uma condição SQL ou um parâmetro de consulta. O teste estabelece se o sistema retorna exatamente o subconjunto prometido pelo contrato.

Ordenação

A ordenação define a ordem dos resultados, geralmente por data, nome, status, prioridade, preço ou outro campo.

O erro mais comum é verificar superficialmente se a ordem parece aproximadamente correta. Na prática, a ordenação precisa ser:

  • →Correta
  • →Estável
  • →Previsível
  • →Compatível com a paginação

Uma ordem estável é especialmente importante. Ordenar apenas por um campo com valores repetidos, como timestamps created_at idênticos ou valores de status, pode tornar inconsistente a ordem dos registros empatados. Com paginação, os usuários podem então ver registros duplicados ou ausentes entre páginas.

QA deve testar empates, além da ordenação comum por um único campo.

O que importa para QA

Algumas verificações são úteis em quase todos os casos.

Para paginação:

  • →A primeira página
  • →A última página
  • →Uma página vazia
  • →Tamanho de página = 1
  • →Tamanho de página no máximo permitido
  • →Tamanho de página acima do limite permitido
  • →Navegação entre páginas adjacentes
  • →Ausência de duplicatas ou omissões entre páginas
  • →Valores corretos de has_more, next_cursor e total_count, quando fornecidos

Para filtragem:

  • →Um filtro
  • →Vários filtros juntos
  • →Valores-limite
  • →Um valor vazio
  • →Um filtro omitido
  • →Um valor de filtro inválido
  • →Filtragem de campos sujeitos a controles de acesso
  • →Filtragem por data e hora

Para ordenação:

  • →Ordem crescente e decrescente
  • →Ordenação por diferentes campos
  • →Vários registros com valores iguais
  • →Ordenação combinada com filtros
  • →Ordenação combinada com paginação
  • →Um campo de ordenação não suportado

Padrões comuns de falha

  • →Um item aparece tanto na primeira quanto na segunda página
  • →Um item desaparece entre páginas
  • →O total_count difere da quantidade real
  • →Um filtro se aplica aos registros, mas não à contagem
  • →A ordem visível muda entre requisições idênticas
  • →Um novo registro desloca posições e prejudica a navegação por offset
  • →O backend ignora silenciosamente uma opção desconhecida de filtro ou ordenação
  • →A interface espera uma ordem enquanto a API retorna outra
  • →Filtros de data produzem resultados diferentes devido aos fusos horários
  • →Filtros e controles de acesso interagem de forma inesperada

Isso é especialmente importante quando as listas são a principal interface de trabalho do produto. Mesmo uma pequena instabilidade pode comprometer rapidamente a confiança do usuário.

Exemplo prático

Considere uma API de listagem de pedidos:

  • →GET /orders?status=paid&sort=created_at_desc&limit=20

QA deve verificar:

  • →Somente pedidos pagos são retornados
  • →Os pedidos são ordenados por data na direção solicitada
  • →Dois pedidos com o mesmo created_at mantêm uma ordem relativa estável
  • →A próxima página não contém duplicatas ou omissões
  • →O total_count, se existir, corresponde ao conjunto filtrado
  • →A paginação se comporta de forma previsível se surgir um novo pedido durante a navegação
  • →Valores inválidos de sort ou status são tratados claramente, sem interromper o serviço

Uma lista pode parecer quase funcional, mas esses detalhes a tornam pouco confiável na prática.

Principais conclusões para QA

  • →Teste paginação, filtragem e ordenação juntas e separadamente.
  • →APIs de listagem frequentemente falham nos limites e nas combinações de condições, além do caminho feliz.
  • →A paginação por offset é simples, mas sensível a mudanças nos dados entre requisições.
  • →A paginação por cursor é mais resistente a mudanças nos dados, mas exige outra abordagem de teste.
  • →Uma ordenação estável é essencial para uma paginação correta.
  • →Verifique total_count, has_more, cursores e limites de páginas com o mesmo cuidado dedicado aos registros.

Leitura adicional

  • →Nesta base de conhecimento: Testes negativos de API
  • →Nesta base de conhecimento: Métodos, códigos de status e cabeçalhos
  • →Recurso externo: Paginação da Stripe

Um conjunto de 12 registros com páginas esperadas conhecidas

O ambiente local começa com IDs 1–12. Score é floor((id−1)/3), portanto três registros consecutivos têm o mesmo score. IDs pares têm status open e ímpares, closed. A ordenação por score usa ID como chave secundária, tornando os empates determinísticos. Execute as verificações a seguir em uma massa de dados nova, sem gravações entre requisições de páginas.

plain text
Consulta	IDs esperados	Total
?sort=score&limit=5&offset=0	1,2,3,4,5	12
?sort=score&limit=5&offset=5	6,7,8,9,10	12
?sort=score&limit=5&offset=10	11,12	12
?sort=score&limit=5&offset=12	(vazio)	12
?status=open&sort=score&limit=5&offset=0	2,4,6,8,10	6
?status=open&sort=score&limit=5&offset=5	12	6

Junte as três primeiras páginas e exija exatamente os IDs 1–12, sem duplicatas ou lacunas. Verifique se total descreve o conjunto filtrado antes da paginação, e não o tamanho da página atual. Neste contrato, limit deve ser de 1 a 5, offset é um inteiro não negativo, e valores não suportados de ordenação ou filtro retornam 400.

Um desempate estável não cria um snapshot. Se os dados mudarem entre requisições por offset, registros poderão atravessar os limites das páginas. Um experimento separado deve definir o contrato de consistência e inserir/excluir registros entre requisições; a paginação por cursor também exige uma ordenação definida e uma política de validade do cursor. O ambiente fornecido exercita o comportamento estático por offset, não essas garantias adicionais.

Continuar aprendendo

Baixe o laboratório de prática local (ZIP)

Inspecione ordenação e filtragem em SQL

Rejeite parâmetros de consulta inválidos