DevSecOps16 min

Des tests qui attrapent vraiment les erreurs : au-delà de la couverture et du quality gate au vert

Par Dorian Chávez · fondateur de Hábil et architecte d'intégration ·

Couverture élevée et quality gate au vert ne suffisent pas : types de tests, doublures qui masquent des défauts, mutation, IA et documentation.

Scénario illustratif. Une équipe paiements d'une fintech ouvre le tableau de bord un vendredi : la couverture de tests est à 91 %, l'analyse de qualité du code affiche vert et le pipeline —la chaîne automatique qui construit, teste et livre le logiciel— s'est terminé sans erreur. Le lundi, un groupe de clients signale des débits en double. Personne n'a menti et aucun outil n'a été défaillant : chacun a mesuré ce qu'il sait mesurer. Ce que personne n'avait mesuré, c'est si les tests, qui étaient nombreux, auraient signalé ce défaut en particulier.

Cet article s'adresse à celles et ceux qui répondent de cet écart : le CTO ou le directeur technique d'une banque, d'une fintech, d'un assureur, d'une enseigne de retail ou d'une entreprise réglementée. Il explique ce que mesurent réellement la couverture et le quality gate (la « porte de qualité » : un ensemble de conditions que le code doit remplir pour avancer), quels types de tests existent et quel défaut chacun attrape, comment on vérifie qu'un test est utile, quel rôle jouent l'intelligence artificielle et la documentation du code, et par où commencer. Il inclut ce que nous avons mesuré sur notre propre plateforme, car certaines de ces constatations ont été inconfortables.

Ce que mesure réellement un tableau de bord au vert

Il convient de commencer par ce que disent les outils eux-mêmes.

La couverture répond à une seule question : cette ligne de code a-t-elle été exécutée pendant que les tests tournaient ? SonarQube, un outil d'analyse de qualité du code, définit la couverture de lignes comme les lignes couvertes sur les lignes exécutables, et celle des conditions comme les branches vraies et fausses parcourues sur le double des conditions [11]. Exécuter une ligne n'est pas vérifier qu'elle fait ce qu'il faut : un test sans aucune vérification (une « assertion », la comparaison entre ce qui était attendu et ce qui s'est produit) peut faire monter la couverture sans rien attraper.

Le quality gate de SonarQube est un ensemble de conditions configurables. Celui par défaut, appelé « Sonar way », demande sur le code nouveau : aucun nouveau problème, une couverture d'au moins 80 %, une duplication de 3 % ou moins et les points sensibles de sécurité revus [10] [Donnée de Sonar : valeurs par défaut du fournisseur] ; chaque organisation les ajuste. La couverture de lignes dit seulement si une ligne a été exécutée ; la métrique globale de Sonar combine lignes et conditions. De plus, Sonar ne génère pas la couverture : il l'importe d'un autre outil qui exécute les tests avant l'analyse [12]. De ce qu'il mesure se déduit ce qu'il ne fait pas : il n'exécute ni un virement, ni un rapprochement, ni une émission de police, ni un paiement dans le commerce électronique. Cette lecture est la nôtre, ce n'est pas une phrase de Sonar, mais elle est cohérente avec ce que décrit sa documentation.

Il n'existe pas non plus de chiffre magique de couverture. Martin Fowler, référence en génie logiciel, la considère comme un outil pour trouver du code non testé, non comme un objectif ; il juge raisonnable une couverture de la fin des 80 % aux 90 %, traite le 100 % comme un signal d'alerte et avertit qu'imposer un minimum incite à écrire des tests vides pour l'atteindre [9]. Une étude académique classique, d'Inozemtseva et Holmes (2014), a constaté que la couverture n'a pas de corrélation forte avec l'efficacité d'un ensemble de tests une fois que l'on neutralise sa taille [21].

Et le « vert » signifie des choses différentes selon la personne qui configure la porte. Lors d'une revue interne de notre plateforme, nous avons constaté que l'analyse d'un projet tout juste créé passait avec 3 conditions actives, alors que celle d'un projet mûr en exigeait 14. La même couleur, deux niveaux d'exigence très différents.

Les deux formes les plus courantes de faux vert

1. Les doublures qui répondent ce que vous attendez

Pour tester vite, les équipes remplacent les éléments externes —la base de données, le prestataire de paiement, un autre service— par des doublures de test : des imitations qui répondent de façon prédéfinie. Fowler en distingue plusieurs types : les stubs (réponses toutes faites), les fakes (implémentations simplifiées mais fonctionnelles), les spies (qui enregistrent la façon dont on les a utilisés) et les mocks (qui portent des attentes préprogrammées) [8]. Elles sont utiles pour que les tests restent rapides et isolés.

Le risque est simple à énoncer : si la doublure répond ce que le programmeur croit que le système réel répond, le test passe même si le système réel répond autre chose. Une doublure peut répondre « 200 OK » alors que le prestataire réel rejette l'en-tête, l'encodage, le certificat ou le format de la date. Fowler souligne en outre que les tests fondés sur des mocks sont plus couplés à l'implémentation : si vous réorganisez le code sans changer ce qu'il fait, ces tests se cassent ; et si le système réel change, ils continuent de passer [7].

C'est pourquoi les tests doivent être menés sur des dépendances réelles là où la décision revient à la dépendance et non à votre code : la base de données avec son vrai moteur, le bus de messages avec le sien, le contrat avec le prestataire vérifié auprès du prestataire. Pour les dépendances que vous pouvez conteneuriser, des outils comme Testcontainers lancent une base de données ou une file réelles et jetables pendant l'exécution du test et les détruisent à la fin ; leur propre guide propose de remplacer les bases en mémoire par la base réelle [13]. Pour les prestataires externes, continuez d'utiliser un bac à sable, un contrat ou une doublure observable : un conteneur ne remplace ni les identifiants, ni l'homologation, ni l'autorisation d'un tiers réel.

2. Les tests qui valident l'erreur

Un test écrit à partir de ce que le code fait, et non de ce qu'il doit faire, certifie le défaut. Un exemple simple : la règle métier dit que les montants de 10 000 pesos ou plus sont bloqués, mais le code ne bloque que ceux supérieurs à 10 000, et le test, écrit en regardant le code, vérifie le comportement actuel. La couverture est complète, tout est au vert et la règle n'est pas respectée. C'est un risque connu des tests écrits par des personnes et, comme nous le verrons, un risque plus grand pour ceux qu'écrit une IA.

Aucune des deux formes ne se voit sur le tableau de bord. Elles se voient en posant d'autres questions à la suite de tests, et c'est l'objet du reste de l'article.

Les types de tests et le défaut que chacun peut attraper

Aucun type de test ne couvre à lui seul tous les risques pertinents. Chaque type peut apporter une preuve que les autres n'apportent pas pour ce flux. Voici la liste que nous utilisons pour l'expliquer à un comité :

Les types de tests et le défaut que chacun peut attraper
TypeCe qu'il exécuteCe qu'il peut attraperCe qu'il ne voit pasOutils d'exemple
UnitaireUne fonction ou une classe isoléeCalculs, limites, validations, règles localesQue les éléments s'emboîtent entre euxJUnit, pytest, Go testing, Jest, Vitest
Intégration avec dépendances réellesVotre code plus une base de données, un bus ou un service réels et jetablesMigrations cassées, requêtes qui échouent face au schéma réel, sérialisation, configuration, transactionsLes parcours complets d'utilisateurTestcontainers
ContratLe consommateur et le fournisseur d'une API, chacun face à ce qui a été convenuUn champ renommé, un type modifié, un en-tête différent qui casserait le consommateurLa logique interne du fournisseurPact
Collection d'APIDes requêtes HTTP contre un environnement, avec des vérificationsCodes de réponse, formats, authentification, autorisation, régressions d'un serviceLe comportement internePostman, Postman CLI, Newman
De navigateur (de bout en bout)Une personne simulée, le navigateur, le frontend et le backend intégrésParcours, cookies, ouverture de session, rendu, flux critiquesLes détails fins ; ils sont lents et fragiles si l'on en abusePlaywright
De mutationVotre suite contre des versions délibérément endommagées du codeDes tests qui exécutent du code sans détecter de changementsSi la règle métier elle-même est la bonnePIT (Java), Stryker (JavaScript/TypeScript, C#, Scala)

Quelques précisions qui comptent pour décider :

  • Contrat. Pact vérifie le fournisseur que l'équipe contrôle ; il ne valide pas nécessairement le tiers réel. Il fonctionne « piloté par le consommateur » : on ne teste que ce que le consommateur utilise réellement ; le consommateur génère un fichier avec ses attentes et le fournisseur le vérifie contre le service réel [14]. Cela évite de monter des tests intégrés coûteux entre deux équipes. Ses propres documents déclarent ses limites : il ne sert pas aux tests fonctionnels, de charge, ni pour les API publiques, ni lorsque l'on ne contrôle pas les deux côtés [14].
  • Collections d'API. Postman permet d'écrire des vérifications en JavaScript par requête, dossier ou collection [15]. Une information pratique que peu de gens mentionnent : Newman, l'outil d'exécution de collections en ligne de commande, reste disponible pour les flux existants, mais son dépôt officiel indique que le développement actif se limite à la maintenance essentielle et que, pour les nouveaux flux, ils recommandent la Postman CLI [16]. Si vous avez déjà des collections qui tournent dans Newman, il n'y a pas d'urgence ; si vous démarrez, mieux vaut commencer avec l'outil en vigueur.
  • Navigateur. Un test de navigateur n'est pas toujours de bout en bout : il peut simuler les tiers. Playwright couvre Chromium, WebKit et Firefox, et ses bonnes pratiques demandent de tester ce que voit l'utilisateur, d'isoler chaque test et de simuler les sites tiers plutôt que de les tester [17]. C'est le type le plus proche de l'usage réel, et c'est pourquoi on le réserve à peu de parcours de forte valeur.
  • Mutation. Elle s'explique en une phrase : saboter le système exprès pour voir si l'alarme sonne. Elle est développée plus loin.

Outils par couche

Les types de tests et le défaut que chacun peut attraper
CoucheOutils d'exempleÀ quoi cela sert
Backend JavaJUnit, Testcontainers, PITRègles métier, intégration avec l'infrastructure, mutation du code critique
Backend Pythonpytest (avec ses fixtures, données et ressources d'appui réutilisables)Règles, paramétrage, intégration
Backend Gotesting et go test, partie de la bibliothèque standard ; prend en charge les tests de fuzzing (entrées aléatoires)Unités, intégration, entrées inattendues
Frontend (JavaScript/TypeScript)Jest ou Vitest, avec Testing LibraryLogique d'interface et composants, testés comme les utilise une personne
Frontend, parcours completsPlaywrightFlux critiques et compatibilité entre navigateurs
JavaScript/TypeScript, mutationStrykerJS sur Jest ou VitestDétecter les tests faibles

Testing Library formule le principe avec clarté : plus un test ressemble à la façon dont le logiciel est utilisé, plus il donne de confiance [20]. Jest déclare que Vite n'est pas officiellement pris en charge et suggère Vitest dans ce cas [20] ; c'est un exemple de la raison pour laquelle l'outil se choisit en fonction du reste de votre pile, et non par effet de mode.

Pourquoi plus de types de tests rapportent plus que plus de tests du même type

L'affirmation correcte n'est pas « plus il y a de types, mieux c'est » sans limite. C'est celle-ci : pour un risque donné, il convient d'investir dans le type de test qui couvre une classe de défauts que personne n'a encore couverte.

Dix tests unitaires de plus sur un arrondi ne vont pas découvrir une migration de base de données qui échoue, un contrat HTTP incompatible, une session qui se perd entre deux écrans ou une dépendance qui met trop de temps. Ce sont d'autres types qui détectent cela. Les données de recherche sur la diversité des tests vont dans ce sens : des critères qui distinguent des comportements différents peuvent trouver des défauts que les critères traditionnels ne voient pas, avec un coût supplémentaire [23].

L'autre moitié de l'équilibre est de ne pas aller à l'extrême inverse. Les tests de navigateur sont les plus proches de l'usage réel, mais aussi les plus lents et les plus fragiles. Fowler les décrit comme fragiles, coûteux à écrire et lents à exécuter [1]. Dans l'étude de Google sur environ 4,2 millions de ses propres tests, les plus gros ont été plus instables, c'est-à-dire qu'ils passent et échouent sans que le code change ; WebDriver et l'émulateur Android ont montré des taux supérieurs à la moyenne parmi les outils analysés, et l'auteur précise lui-même que corrélation n'est pas causalité [5] [Donnée de Google, 2017 ; non universelle]. Son guide recommande, approximativement, 70 % de petits tests, 20 % d'intégration et 10 % de bout en bout [4] [Donnée de Google, 2015 ; non universelle]. C'est une orientation d'une entreprise, non une norme ; certains soutiennent que discuter de pourcentages détourne l'attention [3]. Fowler et Google recommandent de réserver les tests larges aux risques qui le justifient ; la proportion dépend du système, et Fowler avertit que la pyramide admet des exceptions [1][4].

Un exemple pour un comité : trois mille tests unitaires avec doublures, sans tests de contrat, signifient qu'un champ renommé dans une API casse tous ses consommateurs en production sans qu'aucun tableau de bord ne prévienne. Ces mêmes trois mille, sans intégration réelle, signifient que personne n'a testé la requête face au vrai schéma. Et si tout ce qui précède existe mais qu'aucun test ne parcourt le flux complet, personne ne sait si le client peut terminer son achat. Chaque type de test peut couvrir une classe de défauts que les autres ne voient pas ; concentrer tout sur un seul type, c'est concentrer le risque.

Ce que nous avons mesuré sur notre propre plateforme

Hábil construit une plateforme modulaire d'intégration. Lors d'une mesure récente, sur ses 34 services, nous avons compté 1 407 classes de test et environ 9 800 méthodes de test automatisées (deux façons différentes de les compter ont donné 9 771 et 9 839) [37]. Avec une telle quantité, on s'attendrait à être tranquille. Voici des enseignements, déjà corrigés, de cas où la tranquillité n'était pas justifiée. Les chiffres sont les nôtres et n'ont pas été audités de l'extérieur.

Le paiement qui était effectué 12 fois. Un test d'un flux de paiement s'appelait « ne duplique pas » et était au vert. Il vérifiait un compteur interne du service lui-même, non l'appel au prestataire de paiement. Une fois réécrit pour vérifier l'appel réel, il a échoué : on attendait 1 et il y en a eu 2. Avec un serveur factice qui compte combien de fois on l'appelle, 12 tentatives simultanées ont produit 12 paiements. Après la correction, elles en ont produit 1. Remarquez la différence entre deux classes de doublure : l'une qui répond ce qui est attendu, qui cache le défaut, et l'autre qui enregistre ce qui lui parvient réellement, qui l'expose.

Les 17 champs perdus sur 19. Un changement dans une fonction d'extraction de données a passé toute la suite, qui utilisait des documents d'échantillon synthétiques. Avec des documents réels, le changement perdait 3 champs sur 4 pour un type de document et 17 sur 19 pour un document étranger. Les tests n'étaient pas mal écrits : ils étaient alimentés par des données qui ne ressemblaient pas aux vraies.

Le rejet qui coupait un canal. Un rejet légitime du prestataire, répété plusieurs fois, faisait déclencher le disjoncteur (circuit breaker), le mécanisme qui coupe les appels à un service qui semble en panne. L'effet était de couper le canal entier. Il était présent dans 7 services. Les doublures de test ne répétaient pas le rejet, de sorte que le défaut n'avait aucune manière d'apparaître.

Cinq tests verts qui soutenaient des défauts. Nous avons trouvé cinq tests au vert qui soutenaient des défauts, de trois types : celui qui valide l'erreur avec un nom explicite, celui qui simule une issue impossible et celui qui est trop permissif. Exercer le système réel a écarté 9 constatations de notre part et en a confirmé d'autres : vérifier en conditions réelles corrige dans les deux sens.

Le succès sans travail. Deux faux verts de mesure, parmi les plus traîtres : un build qui s'est terminé par le message de succès sans avoir exécuté aucun test, et une exécution de tests passée par un filtre de texte qui a interrompu le processus à mi-chemin et rapporté 113 et 401 tests là où 518 tournaient en réalité. La sortie ressemblait à un décompte valide. Leçon : le nombre de tests se lit dans le rapport, non dans le code de sortie d'une commande.

Les cinq cas ont une racine commune : dans chacun, le signal vert était bien construit et répondait honnêtement à la question qu'on lui posait. La question était la mauvaise.

Comment savoir si un test est utile ?

Il y a deux réponses, l'une artisanale et l'autre automatisée.

L'artisanale : annuler la correction et voir le test passer au rouge. Si un test a été écrit pour protéger une correction, on défait la correction et l'on exécute le test : il doit échouer. S'il reste au vert, il ne protégeait rien. Pour un nouveau défaut, la règle équivalente est d'écrire d'abord le test qui échoue, puis de corriger ; le guide officiel de Claude Code, par exemple, la demande ainsi pour les erreurs [28]. Elle est peu coûteuse et exige de la discipline. Sur notre plateforme, nous l'utilisons comme étalon : les 6 mutations manuelles que nous avons faites ont été détectées.

Il y a un piège plus fin qu'il convient de connaître, car il n'apparaît pas dans la littérature que nous avons consultée : un test peut aussi passer avec le défaut. Dans l'une de nos corrections, le critère disait « après le rejet, le solde revient à sa valeur précédente ». En relisant, nous avons remarqué que cette vérification passait aussi avec l'erreur, car mettre un montant de côté et le restituer laissent le même chiffre. Ce qui distinguait réellement, c'était le registre des opérations : avec le défaut, deux écritures apparaissaient ; avec la correction, aucune. La question qui vaut la peine d'être posée à chaque test important est simple : passerait-il aussi si l'erreur était toujours là ?

L'automatisée : le test de mutation. Des outils comme PIT (pour Java) et Stryker (pour JavaScript, TypeScript, C# et Scala) modifient automatiquement le code —changent un « supérieur à » en « supérieur ou égal à », inversent une condition, suppriment un appel— et exécutent la suite [18][19]. Si un test échoue, le changement « meurt » ; si tous passent, le changement « survit » et révèle un test qui manquait. Le pourcentage de changements détectés s'appelle le mutation score : si, sur 100 sabotages, la suite en attrape 80, le score est de 80 %. PIT le dit clairement : la couverture traditionnelle ne mesure que ce qui s'exécute, non si les tests pourraient détecter une défaillance [18]. Une étude de FSE 2014 a constaté que les mutants sont un substitut valable des défauts réels pour évaluer des tests [22].

La mutation a des limites qu'un CTO doit connaître :

  • Elle est lente. C'est pourquoi il convient de l'appliquer au code qui a changé ou au code critique, non à tout le dépôt ; la documentation de PIT elle-même le recommande [18].
  • Elle a du bruit. Il existe des « mutants équivalents » : des changements qui n'altèrent pas le comportement et qu'aucun test ne pourrait détecter [18]. Une étude industrielle a rapporté que la détection automatique de ces mutants s'améliore beaucoup avec un prétraitement préalable, ce qui indique que le contrôle lui-même a sa marge d'erreur [27].
  • Elle ne certifie pas le métier. Si le test valide une règle erronée, il peut même « tuer » le changement qui corrige le code. La recherche appuie l'usage de la mutation comme guide, non comme indicateur unique : sa relation avec les défauts réels dépend de la taille et du contexte de la suite [23].

C'est pourquoi la qualité se mesure comme un ensemble de signaux, chacun avec sa question :

Comment savoir si un test est utile ?
SignalQuestion à laquelle il répond
CouvertureQuel code a été exécuté ?
MutationLes vérifications détectent-elles des changements plausibles ?
Contrats vérifiésLe consommateur et le fournisseur sont-ils toujours compatibles ?
API et navigateur sur des parcours critiquesLe flux réel fonctionne-t-il dans l'environnement visé ?
Traçabilité entre exigence et testL'attente vient-elle d'une règle approuvée, ou de ce que le code faisait déjà ?
Défauts arrivés en productionLa preuve continue-t-elle de prédire ce qui se passe en production ?

Même avec des dépendances réelles, des choses peuvent arriver

Mener les tests sur des dépendances réelles réduit une classe de risque ; cela ne l'élimine pas. Un environnement de test n'est pas la production : il a moins de données, une autre latence, d'autres identifiants et, souvent, une autre version du prestataire. Un tiers peut changer son comportement sans prévenir. Une charge qui n'a pas été simulée peut révéler un défaut de concurrence. Et les flux qui n'ont lieu qu'une fois par mois, comme la clôture comptable ou le renouvellement annuel d'une police, sont rarement dans la suite. Cette carte couvre principalement le comportement fonctionnel et la compatibilité ; la performance, la sécurité et la continuité exigent des contrôles spécifiques selon le risque.

C'est pourquoi la stratégie sensée a deux moitiés. La première : davantage de types de tests automatisés, chacun visant une classe de défauts. La seconde : ce qui se passe après la mise en production — observer ce que fait le système, pouvoir revenir en arrière et examiner à tête reposée ce qui a échappé. Chaque défaut qui arrive en production est une information : il indique quel type de test manquait, et la bonne réponse est généralement d'ajouter ce test, pas seulement de corriger le code. Cette conversation, celle de la mise en production maîtrisée, nous la développons dans « Livrer sans crainte sur votre propre infrastructure ».

L'intelligence artificielle : elle accélère, mais elle a besoin d'un filtre

L'IA aide à construire des tests : elle propose des cas limites, génère des squelettes, monte des collections d'API, explique une défaillance. Ce qu'elle produit a un profil connu.

Ce que montrent les données. Une étude industrielle de Meta sur la génération de tests avec des modèles de langage a mesuré que 75 % des cas compilaient, 57 % passaient de façon fiable et 73 % des recommandations ont été acceptées par les ingénieurs [Étude de Meta, échantillon spécifique] ; tout cela après des filtres automatiques qui écartent ce qui ne compile pas, ne passe pas ou n'apporte pas de couverture [24]. Une étude sur 25 paquets JavaScript a relevé une médiane de 70,2 % de couverture d'instructions et de 52,8 % de branches avec un modèle généraliste [25]. Ce sont des chiffres de modèles de 2023 et 2024 ; ceux d'aujourd'hui seront différents, mais la direction est instructive : sans filtres, une part importante de ce qui est généré ne sert pas.

Le risque central. L'IA tend à copier ce que le code fait, non ce qu'il doit faire. Une étude sur 24 dépôts Java a conclu que les tests générés avec des modèles de langage capturent surtout le comportement actuel, ce qui rend la détection d'erreurs plus difficile [26]. C'est le test qui valide l'erreur, produit à vitesse de machine. Autres risques documentés : des vérifications superficielles qui gonflent la couverture, des méthodes ou des règles inventées, et des données sensibles qui partent vers un tiers. Une étude historique sur un assistant de code a trouvé des vulnérabilités dans environ 40 % de 1 689 programmes générés pour des scénarios précis ; c'est un résultat de son époque, non un taux applicable aux modèles actuels [36].

Que faire de cela. Les guides des fournisseurs convergent sur l'essentiel, même si aucun n'apporte de chiffres propres :

  • Donner à l'IA une vérification qu'elle peut exécuter elle-même ; le guide de Claude Code l'appelle la différence entre une session que l'on surveille et une que l'on laisse seule, et demande qu'elle montre la sortie des tests au lieu d'affirmer qu'ils ont passé [28].
  • Être précis en demandant des tests : « ajoute des tests à ce fichier » est le mauvais exemple ; le bon nomme le cas limite et ce qu'il faut éviter [28].
  • Relire ce qui est généré et ajouter les tests qui manquent, comme l'indique le guide de GitHub Copilot [30].
  • Surveiller le « vert à tout prix » : le guide d'Anthropic avertit que le modèle peut se concentrer sur le fait que les tests passent, même avec des valeurs figées, et rappelle que les tests sont là pour vérifier l'exactitude, non pour définir la solution [29].
  • Séparer celui qui écrit de celui qui relit. Le guide de Claude Code suggère des sessions distinctes pour écrire les tests et pour écrire le code qui les satisfait [28].
  • Ne chargez pas de données de production dans des outils d'IA ni dans des environnements de test sans classification, masquage (ou données synthétiques) et validation de la vie privée, et vérifiez avec votre fournisseur la conservation et les conditions contractuelles.
  • Faire passer ce qui est généré par la mutation : donner à l'IA les mutants qui ont survécu a permis de détecter jusqu'à 28 % de fragments défectueux de code écrit par des personnes en plus que la ligne de base, dans une étude [27].

La politique qui résume tout est courte : l'IA propose ; l'exécution, la mutation et la relecture par le métier valident.

Pourquoi documenter le code améliore les tests

Le code ne dit que ce qu'il fait. Ce qu'il doit faire vit ailleurs, et si ce n'est pas écrit, l'IA —et la personne nouvelle dans l'équipe— le déduit de l'implémentation et copie ses erreurs. C'est là qu'intervient la documentation.

Les commentaires de documentation —Javadoc en Java, JSDoc et TSDoc en JavaScript et TypeScript, docstrings en Python— sont, en pratique, un contrat : ce qu'une fonction reçoit, ce qu'elle renvoie, quelles exceptions elle peut lever, quels effets de bord elle a [34]. La convention de Python (PEP 257) demande de documenter le comportement, les arguments, le retour, les effets de bord, les exceptions et les restrictions d'usage [34]. De plus, doctest transforme les exemples écrits dans la docstring en tests exécutables : si un exemple cesse d'être vrai, la suite le signale [34] ; ce que la docstring explique en dehors de ces exemples peut, lui, devenir obsolète en silence.

Quelle est la part de preuve que cela améliore les tests ? La réponse honnête est : cela va dans ce sens, mais nous n'avons pas trouvé d'expérience contrôlée du type « même code avec et sans documentation ». Ce qui existe, ce sont des études voisines : convertir de la documentation en langage naturel en conditions vérifiables avec un modèle de langage a permis d'attraper 64 erreurs historiques réelles [33] ; extraire des règles de la documentation d'API d'apprentissage profond a trouvé 94 erreurs contre 59 pour la ligne de base sans ces contraintes [33] ; et une étude de génération de vérifications a constaté des améliorations de 10 à 20 % en intégrant la Javadoc [31]. L'avertissement va dans l'autre sens : une documentation fausse ou périmée peut nuire gravement à la compréhension du code par un modèle [32]. Il ne suffit pas de documenter ; il faut maintenir ce qui est documenté exact.

Le troisième élément, ce sont les fichiers de contexte du dépôt, comme AGENTS.md (format ouvert que lisent plusieurs assistants de code, dont Codex et Copilot) ou CLAUDE.md dans le cas de Claude Code [35]. On y écrit les commandes pour lancer les tests, les conventions et les pièges que l'on ne déduit pas en lisant le code. Deux recommandations officielles : qu'ils soient courts, car s'ils sont longs l'assistant ignore des règles, et qu'ils ne remplacent pas les exigences approuvées ni ne contiennent de secrets [28][35].

Sur notre plateforme, nous documentons le code pour qu'une personne nouvelle puisse s'orienter sans aide. Nous n'avons pas mesuré que cela ait amélioré les tests qu'écrivent les assistants, et nous ne l'affirmons pas. Ce que nous avons mesuré, c'est le coût de ne pas l'écrire : la documentation disait déjà qu'une certaine option de configuration n'était pas exercée en dehors de sa valeur par défaut, et le trou est apparu quand même. De là est sortie une règle pratique : un test de configuration doit démontrer les deux directions, pas seulement la plus courante.

Exemples simples par secteur

Ce sont tous des scénarios illustratifs, sans clients ni chiffres.

Exemples simples par secteur
SecteurScénarioQuelle combinaison de tests l'attrape
BanqueUn virement est dupliqué quand l'application réessaie après une connexion coupéeUnitaire de l'idempotence (le fait que répéter la même opération ne l'applique pas deux fois : réessayer ne répète pas) ; intégration avec la base réelle pour vérifier que la contrainte d'unicité fonctionne ; contrat avec le service de paiements ; parcours de navigateur du virement au justificatif
FintechUn dépôt est crédité deux fois quand le prestataire répète l'avisUnitaire de la clé d'idempotence et des montants ; intégration avec le grand livre de soldes réel ; contrat de l'avis ; collection d'API pour la signature invalide
AssuranceLa tarification applique une franchise erronée précisément à l'âge limiteUnitaire avec les âges de frontière (70 et 71, avec et sans examen médical) ; mutation du moteur de tarifs, car là un « supérieur à » changé en « supérieur ou égal à » modifie les primes ; parcours du devis à l'émission
RetailLe checkout vend la dernière pièce à deux clients en même tempsIntégration avec le stock réel et concurrence ; contrat avec les paiements ; quelques tests de navigateur du parcours d'achat, avec la passerelle externe simulée
Entreprise réglementéeUn rapport réglementaire affiche un total mal agrégéUnitaires des règles de calcul ; intégration contre le schéma réel ; mutation sur la logique d'agrégation ; une exigence écrite dans le contexte du dépôt qui impose un test de masquage des données personnelles dans les journaux

Prenez celui de la banque. L'unitaire dit que la logique est correcte ; celui d'intégration démontre que la base rejette réellement le doublon ; celui de contrat dit que le service de paiements comprend la même identification ; celui de navigateur, que la personne voit un justificatif. Aucun des quatre n'apporte seul la preuve des trois autres.

Par où commencer

  1. Mesurez ce que vous avez déjà, de deux façons. Comptez vos tests à partir du rapport de l'exécution, non du code de sortie, et comparez avec une autre méthode. Examinez quelles conditions actives votre quality gate a dans chaque projet et si ce sont les mêmes.
  2. Choisissez vos cinq flux où il y a le plus d'argent ou de réglementation en jeu —un paiement, une émission, un rapprochement, un rapport— et demandez pour chacun : quel type de test l'attraperait s'il se cassait, et existe-t-il aujourd'hui ?
  3. Revoyez vos doublures. Là où la dépendance décide (base, bus, prestataire), passez d'une doublure qui répond ce qui est attendu à une dépendance réelle ou à une doublure qui enregistre ce qui arrive réellement.
  4. Testez vos tests. Choisissez les dix plus importants : annulez la correction et vérifiez qu'ils passent au rouge. Sur le code critique, évaluez un outil de mutation limité à ce qui change.
  5. Placez l'IA sous le même contrôle. Qu'elle montre la sortie des tests, qu'elle ne clôture pas une tâche avec des vérifications vides et que chaque test généré ait une exigence écrite derrière lui.
  6. Écrivez ce que le système doit faire là où les assistants le liront : documentation des règles critiques et un fichier de contexte court avec les commandes et les pièges.

Lors d'un diagnostic, avec un périmètre convenu, nous pouvons construire une carte de vos flux critiques, des preuves existantes et des écarts priorisés. Elle ne remplace pas une certification d'absence de défauts ni de conformité. Combien des tests qui soutiennent aujourd'hui votre vert passent au rouge si l'on annule la correction ? C'est la prochaine étape naturelle : le diagnostic peut commencer par y répondre avec vos propres flux.

Références

  1. M. Fowler, Test Pyramid (2012). https://martinfowler.com/bliki/TestPyramid.html
  2. H. Vocke, The Practical Test Pyramid (2018). https://martinfowler.com/articles/practical-test-pyramid.html
  3. K. C. Dodds, The Testing Trophy and Testing Classifications (2018). https://kentcdodds.com/blog/the-testing-trophy-and-testing-classifications
  4. Google Testing Blog, Just Say No to More End-to-End Tests (2015). Guide d'une entreprise, chiffres approximatifs. https://testing.googleblog.com/2015/04/just-say-no-to-more-end-to-end-tests.html
  5. Google Testing Blog, Where do our flaky tests come from? (2017). Donnée de Google, non universelle. https://testing.googleblog.com/2017/04/where-do-our-flaky-tests-come-from.html
  6. Google Testing Blog, Test Sizes (2010). https://testing.googleblog.com/2010/12/test-sizes.html
  7. M. Fowler, Mocks Aren't Stubs. https://martinfowler.com/articles/mocksArentStubs.html
  8. M. Fowler, Test Double. https://martinfowler.com/bliki/TestDouble.html
  9. M. Fowler, Test Coverage. https://martinfowler.com/bliki/TestCoverage.html
  10. SonarQube, Introduction to quality gates (valeurs par défaut du fournisseur, configurables), consulté le 6 octobre 2026. https://docs.sonarsource.com/sonarqube-server/quality-standards-administration/managing-quality-gates/introduction-to-quality-gates
  11. SonarQube, Metrics definition (couverture de lignes et de conditions), consulté le 6 octobre 2026. https://docs.sonarsource.com/sonarqube-server/user-guide/code-metrics/metrics-definition
  12. SonarQube, Test coverage overview, consulté le 6 octobre 2026. https://docs.sonarsource.com/sonarqube-server/analyzing-source-code/test-coverage/overview
  13. Testcontainers, documentation et guides, consulté le 6 octobre 2026. https://java.testcontainers.org/ · https://testcontainers.com/guides/
  14. Pact, documentation (How Pact works, What is Pact good for), consulté le 6 octobre 2026. https://docs.pact.io/ · https://docs.pact.io/getting_started/what_is_pact_good_for
  15. Postman, Test scripts et Postman CLI overview, consulté le 6 octobre 2026. https://learning.postman.com/docs/tests-and-scripts/write-scripts/test-scripts/ · https://learning.postman.com/docs/postman-cli/postman-cli-overview/
  16. Newman, dépôt officiel (README : maintenance limitée ; Postman CLI pour les nouveaux flux), consulté le 6 octobre 2026. https://github.com/postmanlabs/newman
  17. Playwright, Introduction, Best practices et Mock APIs, consulté le 6 octobre 2026. https://playwright.dev/docs/intro · https://playwright.dev/docs/best-practices · https://playwright.dev/docs/mock
  18. PIT Mutation Testing, site, mutateurs et FAQ, consulté le 6 octobre 2026. https://pitest.org/ · https://pitest.org/faq/
  19. Stryker Mutator, documentation, consulté le 6 octobre 2026. https://stryker-mutator.io/docs/
  20. Documentation officielle de JUnit, pytest, Go testing, Jest, Vitest et Testing Library, consulté le 6 octobre 2026. https://docs.junit.org/current/user-guide/ · https://docs.pytest.org/en/stable/ · https://pkg.go.dev/testing · https://jestjs.io/docs/getting-started · https://vitest.dev/guide/ · https://testing-library.com/docs/
  21. L. Inozemtseva et R. Holmes, Coverage Is Not Strongly Correlated with Test Suite Effectiveness, ICSE 2014. https://dl.acm.org/doi/10.1145/2568225.2568271
  22. R. Just et al., Are Mutants a Valid Substitute for Real Faults in Software Testing?, FSE 2014. https://dl.acm.org/doi/10.1145/2635868.2635929
  23. M. Papadakis et al., mutation et défauts réels, ICSE 2018 (https://doi.org/10.1145/3180155.3180183) ; Shin, Papadakis et Kintis, diversité des tests et mutation, IEEE TSE (https://doi.org/10.1109/TSE.2017.2732347).
  24. N. Alshahwan et al., Automated Unit Test Improvement using Large Language Models at Meta, FSE 2024, arXiv 2402.09171. https://arxiv.org/abs/2402.09171
  25. Schäfer et al., An Empirical Evaluation of Using Large Language Models for Automated Unit Test Generation, arXiv 2302.06527. https://arxiv.org/abs/2302.06527
  26. Étude des oracles de test générés avec des modèles de langage (24 dépôts Java), arXiv 2410.21136. https://arxiv.org/abs/2410.21136
  27. Tests avec modèles de langage et mutation : arXiv 2308.16557 (mutants survivants dans le prompt, jusqu'à 28 % de fragments défectueux détectés en plus) et arXiv 2501.12862 (mutation ciblée dans l'industrie). https://arxiv.org/abs/2308.16557 · https://arxiv.org/abs/2501.12862
  28. Anthropic, Claude Code, Best practices et Memory, consulté le 6 octobre 2026. https://code.claude.com/docs/en/best-practices · https://code.claude.com/docs/en/memory
  29. Anthropic, Claude prompting best practices, consulté le 6 octobre 2026. https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/claude-prompting-best-practices
  30. GitHub, Copilot: write tests et Best practices, consulté le 6 octobre 2026. https://docs.github.com/en/copilot/tutorials/write-tests · https://docs.github.com/en/copilot/get-started/best-practices
  31. Liu et al., Doc2OracLL, 2025. https://doi.org/10.1145/3729354
  32. Macke et Doyle, documentation et compréhension du code par les modèles de langage, NAACL Findings 2024. https://aclanthology.org/2024.findings-naacl.66/
  33. Documentation comme intrant des tests : arXiv 2310.01831 (nl2postcond : langage naturel vers conditions vérifiables, 64 erreurs historiques réelles de Defects4J) et arXiv 2109.01002 (DocTer : règles extraites de la documentation d'API d'apprentissage profond, 94 erreurs contre 59 pour la ligne de base). https://arxiv.org/abs/2310.01831 · https://arxiv.org/abs/2109.01002
  34. Oracle, spécification des commentaires Javadoc ; JSDoc ; TSDoc ; PEP 257 ; documentation de doctest, consulté le 6 octobre 2026. https://docs.oracle.com/en/java/javase/21/docs/specs/javadoc/doc-comment-spec.html · https://jsdoc.app/about-getting-started · https://tsdoc.org/ · https://peps.python.org/pep-0257/ · https://docs.python.org/3/library/doctest.html
  35. AGENTS.md (format ouvert) et documentation de Codex et de GitHub Copilot sur les instructions du dépôt, consulté le 6 octobre 2026. https://agents.md/ · https://learn.chatgpt.com/docs/agent-configuration/agents-md · https://docs.github.com/en/copilot/reference/custom-instructions-support
  36. Pearce et al., Asleep at the Keyboard? Assessing the Security of GitHub Copilot's Code Contributions, IEEE Symposium on Security and Privacy, 2022 (https://doi.org/10.1109/SP46214.2022.9833571) ; version dans Communications of the ACM, 2025 (https://doi.org/10.1145/3610721).
  37. Hábil, mesures propres sur sa plateforme modulaire (34 services), 2026. Expérience de la maison, sans audit externe.