Pagination, filtrage et tri

Détecter les défauts courants des API de listes et tester en détail la pagination, les filtres et le tri.

Mis à jour:

Sommaire

Les API de listes semblent simples, mais recèlent de nombreux défauts gênants. Vérifier seulement l’ouverture d’une liste peut laisser passer des enregistrements absents ou dupliqués, un ordre instable, des totaux incorrects, des filtres défaillants et des incohérences entre pages.

Les listes sont partout : utilisateurs, commandes, paiements, journaux, événements, produits, tâches et commentaires. Une pagination, un filtrage ou un tri mal conçus donnent une impression de désordre : des lignes disparaissent ou se répètent, les filtres surprennent, l’ordre change et la page suivante présente des données incohérentes.

Pourquoi les API ont-elles besoin de ces fonctions ?

Un serveur peut renvoyer tous les enregistrements lorsqu’ils sont peu nombreux. Avec la croissance des données, les réponses s’alourdissent, leur affichage devient difficile pour le client et le backend consomme inutilement des ressources.

  • →La pagination renvoie les données par portions
  • →Le filtrage renvoie le sous-ensemble demandé
  • →Le tri définit l’ordre des éléments

Ces mécanismes fonctionnent presque toujours ensemble. Un utilisateur ouvre une liste de commandes, filtre par statut, trie par date et parcourt les pages. Une instabilité à l’un de ces niveaux perturbe toute l’expérience.

Pagination

La pagination divise un grand jeu de données en pages ou en lots.

  • →Pagination par décalage : page=2, limit=20 ou offset=20&limit=20
  • →Pagination par curseur : cursor=..., starting_after=..., next_page_token=...

Les testeurs QA doivent comprendre la différence.

La pagination par décalage est lisible et fréquente dans les interfaces d’administration et les API CRUD ordinaires. Sa faiblesse : le contenu des pages peut se déplacer lorsque les données changent entre les requêtes. Un utilisateur voit 20 lignes sur la première page ; quelqu’un ajoute une ligne ; la deuxième page contient alors un doublon ou omet un enregistrement.

La pagination par curseur résiste généralement mieux aux données changeantes. Elle convient aux grandes listes fréquemment mises à jour, aux flux d’événements, aux transactions et aux systèmes à forte charge. Le test visuel est plus délicat : il faut suivre un curseur et l’ordre des éléments au lieu d’un numéro de page familier.

En QA, il faut donc tester la pagination avec des données changeantes autant qu’avec un jeu statique.

Filtrage

Le filtrage restreint un jeu de données selon des conditions.

  • →status = active
  • →created_at >= date
  • →price compris entre X et Y
  • →owner_id = utilisateur courant
  • →Recherche par nom ou adresse e-mail
  • →Plusieurs filtres appliqués ensemble

Cette fonction utile est aussi une source fréquente de défauts logiques.

  • →Un filtre est partiellement ignoré
  • →Deux filtres se comportent différemment ensemble et séparément
  • →Un filtre vide et un filtre absent sont traités différemment
  • →La sensibilité à la casse surprend
  • →Le filtrage par date échoue à cause des fuseaux horaires
  • →Le filtrage du backend diffère des attentes de l’UI
  • →Les permissions masquent certains enregistrements et font croire à un filtre défaillant

Tester le filtrage dépasse la vérification d’une condition SQL ou d’un paramètre de requête. Il s’agit d’établir que le système renvoie exactement le sous-ensemble promis par son contrat.

Tri

Le tri définit l’ordre des résultats, souvent selon la date, le nom, le statut, la priorité, le prix ou un autre champ.

L’erreur la plus fréquente est de vérifier superficiellement que l’ordre semble à peu près correct. En pratique, le tri doit être :

  • →Correct
  • →Stable
  • →Prévisible
  • →Compatible avec la pagination

Un ordre stable est essentiel. Trier uniquement par un champ contenant des valeurs répétées, comme des horodatages created_at ou des statuts identiques, peut laisser varier l’ordre des ex æquo. Avec la pagination, des enregistrements peuvent alors apparaître en double ou manquer entre les pages.

Testez les valeurs ex æquo autant que le tri ordinaire sur un seul champ.

Ce qui compte en QA

Certaines vérifications sont utiles dans presque tous les cas.

Pour la pagination :

  • →La première page
  • →La dernière page
  • →Une page vide
  • →Une taille de page de 1
  • →La taille de page maximale autorisée
  • →Une taille de page supérieure à la limite
  • →Le passage entre pages voisines
  • →L’absence de doublons et d’omissions entre les pages
  • →Des valeurs correctes de has_more, next_cursor et total_count lorsqu’elles sont fournies

Pour le filtrage :

  • →Un seul filtre
  • →Plusieurs filtres ensemble
  • →Les valeurs limites
  • →Une valeur vide
  • →Un filtre absent
  • →Une valeur de filtre invalide
  • →Le filtrage de champs soumis au contrôle d’accès
  • →Le filtrage par date et heure

Pour le tri :

  • →Les ordres croissant et décroissant
  • →Le tri selon différents champs
  • →Plusieurs enregistrements de même valeur
  • →Le tri combiné aux filtres
  • →Le tri combiné à la pagination
  • →Un champ de tri non pris en charge

Défaillances courantes

  • →Un élément apparaît sur la première et la deuxième page
  • →Un élément disparaît entre les pages
  • →total_count diffère du nombre réel
  • →Un filtre s’applique aux enregistrements, mais pas au décompte
  • →L’ordre visible change entre des requêtes identiques
  • →Un nouvel enregistrement décale les positions et perturbe la navigation par offset
  • →Le backend ignore silencieusement un filtre ou une option de tri inconnus
  • →L’UI attend un ordre alors que l’API en renvoie un autre
  • →Les filtres de date donnent des résultats différents selon les fuseaux horaires
  • →Les filtres et les contrôles d’accès interagissent de façon inattendue

Ces points sont essentiels lorsque les listes constituent l’interface de travail principale du produit. Même une faible instabilité peut rapidement dégrader la confiance.

Exemple pratique

Prenons une API de liste de commandes :

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

Vérifications QA :

  • →Seules les commandes payées sont renvoyées
  • →Les commandes sont triées par date dans le sens demandé
  • →Deux commandes avec le même created_at conservent un ordre relatif stable
  • →La page suivante ne contient ni doublon ni omission
  • →total_count, s’il existe, correspond au jeu de données filtré
  • →La pagination se comporte de façon prévisible si une nouvelle commande apparaît pendant la navigation
  • →Les valeurs invalides de sort ou status sont traitées clairement sans défaillance du service

Une liste peut sembler presque fonctionnelle tout en restant peu fiable à cause de ces détails.

Points essentiels pour les testeurs QA

  • →Testez la pagination, le filtrage et le tri ensemble et séparément.
  • →Les API de listes échouent souvent aux limites et aux combinaisons de conditions, au-delà du parcours nominal.
  • →La pagination par offset est simple, mais sensible aux changements de données entre requêtes.
  • →La pagination par curseur résiste mieux aux données changeantes, mais exige une approche de test différente.
  • →Un tri stable est indispensable à une pagination correcte.
  • →Vérifiez total_count, has_more, les curseurs et les limites des pages aussi soigneusement que les enregistrements.

Lectures complémentaires

  • →Dans cette base de connaissances : tests négatifs des API
  • →Dans cette base de connaissances : méthodes, codes de statut et en-têtes
  • →Ressource externe : Pagination Stripe

Un jeu de 12 enregistrements avec des pages attendues connues

L’environnement local démarre avec les ID 1–12. Le score vaut floor((id−1)/3), donc trois enregistrements consécutifs partagent le même score. Les ID pairs ont le statut open et les impairs closed. Le tri par score utilise l’ID comme clé secondaire pour départager les égalités de façon déterministe. Exécutez ces vérifications sur un environnement neuf, sans écriture entre les requêtes de page.

plain text
Requête	ID attendus	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	(vide)	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

Réunissez les trois premières pages et exigez exactement les ID 1–12, sans doublon ni omission. Vérifiez que total décrit le jeu filtré avant pagination, pas la longueur de la page courante. Selon ce contrat, limit doit être compris entre 1 et 5, offset est un entier positif ou nul, et les valeurs de tri ou de filtre non prises en charge renvoient 400.

Un départage stable ne crée pas un instantané des données. Si elles changent entre les requêtes par offset, des lignes peuvent franchir les limites des pages. Une expérience distincte doit définir le contrat de cohérence et effectuer des insertions/suppressions entre les requêtes ; la pagination par curseur exige aussi un ordre et une politique de validité des curseurs. L’exercice fourni teste le comportement statique par offset, pas ces garanties supplémentaires.

Pour aller plus loin

Télécharger le laboratoire local de pratique (ZIP)

Inspecter le tri et le filtrage en SQL

Refuser les paramètres de requête invalides