Aller au contenu principal

20. Les tests : produire des preuves, pas cocher une case

Pourquoi ce chapitre existe

« Écrire des tests » semble être une recommandation incontestable. Elle est pourtant insuffisante : un test peut passer tout en protégeant le mauvais comportement, être si couplé à l'implémentation qu'il empêche le refactoring, ou être si lent qu'il n'aide plus personne à décider. À l'inverse, l'absence d'unité testable ne signifie pas automatiquement l'absence de preuve ; une règle peut être protégée par un contrat, une simulation, un rapprochement ou une observation de production.

La question d'ingénierie n'est donc pas combien de tests écrire. C'est : quelle affirmation importante ce changement doit-il rendre crédible, et quelle preuve est proportionnée à son risque ?

Les idées essentielles

  • Un test est une expérience qui relie des conditions à une attente observable.
  • Une preuve est forte lorsqu'elle est proche du risque étudié, déterministe, lisible et difficile à satisfaire par accident.
  • Aucun niveau de test ne prouve tout ; une stratégie équilibre précision, réalisme, vitesse et coût de diagnostic.
  • Les tests servent à la fois à prévenir une régression, à expliquer le comportement et à accélérer l'apprentissage.

Partir d'une affirmation falsifiable

« La remise fonctionne » n'est pas testable. « Une commande ne reçoit jamais une remise supérieure à son montant éligible, quelle que soit la combinaison de coupons applicables » l'est. Cette formulation conduit à des cas représentatifs, des bornes et des invariants. Elle évite d'écrire un test qui reproduit l'implémentation sans interroger le résultat.

Pour chaque changement important, l'équipe peut associer trois éléments : le comportement à préserver ou introduire, le dommage s'il est faux, et la preuve qui rendrait cet écart visible. Cette discipline révèle les angles morts : un test local peut valider le calcul, mais pas le schéma publié ; un test de parcours peut valider l'intégration, mais pas la performance sous charge.

RisquePreuve souvent pertinenteAngle mort à reconnaître
Règle métierCas de décision, propriétés ou invariantsIntégration avec les données et transports réels
Régression d'APITest de contrat producteur-consommateurParcours métier de bout en bout
MigrationContraintes, comptes attendus, réconciliationComportements d'anciens clients non simulés
Incident opérationnelTest de résilience, alerte, exercice de runbookVariabilité complète de production

Les tests doivent échouer pour une bonne raison

Un test utile indique quel comportement a changé et pourquoi cela compte. S'il échoue au gré de l'heure, d'un ordre d'exécution, d'une donnée partagée ou d'un réseau externe, il érode la confiance dans toute la suite. Les tests instables ne sont pas une nuisance mineure : ils enseignent aux équipes à ignorer les signaux, précisément l'inverse de ce que doit produire une stratégie de qualité.

Préférer l'intention au détail de construction

Un test peut légitimement vérifier une interaction lorsqu'elle fait partie du contrat — un paiement n'est débité qu'une fois, un événement est publié. Il devient fragile lorsqu'il vérifie chaque appel interne uniquement parce que c'est facile à observer. Formuler l'attente dans le vocabulaire du domaine protège mieux le comportement et autorise les améliorations de structure.

Anti-patterns

Traiter la couverture comme objectif de qualité

La couverture mesure les lignes ou branches exécutées, non la pertinence des attentes. Elle peut révéler une zone sans aucun test ; elle ne doit pas devenir un seuil qui incite à exécuter du code sans l'interroger.

Ajouter un test après l'incident sans comprendre le mécanisme

Un incident peut justifier un test de non-régression. S'il provient aussi d'un contrat ambigu, d'une donnée historique ou d'une alerte absente, le test seul laisse intacte la famille de risques. L'action doit couvrir la cause systémique identifiée.

Simuler tout le monde

Des mocks très détaillés donnent un contrôle total mais reproduisent souvent les hypothèses de l'auteur. Ils sont utiles pour isoler une décision ; ils ne remplacent pas une preuve contre le contrat réellement fourni par une dépendance.

Bonnes pratiques

Tenir une carte de preuves légère

Pour un parcours sensible, documenter les propriétés importantes et les mécanismes qui les couvrent. Cette carte peut vivre dans la PR, la spécification ou la documentation du service. Elle évite les doublons de tests et rend visibles les risques volontairement non couverts.

Investir dans la vitesse de diagnostic

Un échec rapide, déterministe et précis raccourcit le cycle de développement. Les équipes devraient suivre et traiter la lenteur, l'instabilité et l'opacité de la suite comme des problèmes de produit interne, car elles modifient directement la capacité à prendre de bonnes décisions.

Checklist — Une preuve est-elle utile ?

  • Quelle affirmation de comportement cette preuve soutient-elle ?
  • Quel risque ou quel dommage rend cette affirmation importante ?
  • Le test échouerait-il si le comportement changeait réellement de manière dangereuse ?
  • Est-il déterministe, lisible et suffisamment rapide pour être utilisé au bon moment ?
  • Quel angle mort reste-t-il après son passage ?
  • Qui saura interpréter l'échec et agir dessus ?

À retenir

Les tests ne sont pas une collection de fichiers verts. Ce sont des preuves ciblées qui rendent un comportement discutable, protègent les invariants et raccourcissent le délai entre une erreur et sa compréhension.