Test After, Test First, TDD : ce que chaque approche garantit vraiment


“On fait du TDD” - vraiment ?

Dans beaucoup d’équipes, “on fait du TDD” signifie en réalité : on écrit des tests. Après avoir codé. En espérant couvrir les cas importants.

C’est du Test After. Ce n’est pas du TDD. Et la différence n’est pas qu’une question de timing - elle détermine ce que les tests peuvent détecter.

Les trois approches

Test After - la réalité de beaucoup d’équipes

On écrit le code d’abord. On ajoute les tests ensuite. Si on a le temps.

Ce que ça garantit : que le code testé se comporte comme on l’a écrit. C’est-à-dire : les tests capturent l’état actuel du code, bugs compris.

Le problème central : le biais de confirmation. Quand on a écrit le code, on écrit les tests pour qu’ils passent. On ne cherche pas à trouver des bugs - on cherche à valider ce qu’on a fait. Résultat : les cas limites sont systématiquement sous-testés.

Un deuxième problème : le couplage à l’implémentation. Quand on écrit les tests après le code, on connaît déjà les détails internes - et on les teste. On vérifie que telle méthode est appelée, que tel objet est instancié, que les données transitent dans tel ordre. Ce n’est pas tester un comportement, c’est tester une implémentation. Résultat : le moindre refactoring casse les tests, même si le comportement externe n’a pas changé. Ces tests freinent l’évolution du code au lieu de la protéger.

L’illusion de l’IA. Le développement assisté par agents IA rend le Test After particulièrement séduisant : l’agent génère le code, puis génère les tests, à une vitesse impressionnante. Ça ressemble à de la productivité. En réalité, les deux problèmes s’aggravent : le biais de confirmation est total (l’agent écrit les tests pour valider ce qu’il vient de produire), et le couplage à l’implémentation est maximal (il connaît chaque détail interne qu’il a lui-même généré). Mon avis : ça permet juste de faire de la merde plus vite.

Ce qu’on invoque comme valeur : la non-régression. Les tests écrits après coup peuvent détecter des régressions futures. Mais Test First et TDD offrent la même protection - avec en plus la détection de bugs et une meilleure conception. Il n’y a pas de bonne raison de faire du Test After, à part qu’on ne sait pas faire mieux.

Test First - l’architecture déjà connue

On écrit les tests avant d’écrire le code - plusieurs à la fois, couvrant les comportements attendus, avant que la moindre ligne d’implémentation n’existe.

Ce que ça garantit : que le code est conçu pour être testable, et que les comportements attendus sont explicités avant l’implémentation.

Sa limite : il faut déjà savoir comment le code va être structuré. On écrit un test pour UserRepository.FindByEmail, ce qui suppose qu’on a décidé qu’il y aura un UserRepository avec une méthode FindByEmail. C’est difficile quand on explore un nouveau domaine.

Cas typique : développement avec des specs complètes et une architecture établie. On sait ce qu’on va construire, on formalise d’abord le contrat.

TDD - le test comme outil de conception

On n’écrit pas juste le test avant le code. Le test guide l’écriture du code. Le cycle est : Red → Green → Refactor.

Red    : écrire un test qui échoue (il n'y a pas encore de code)
Green  : écrire le minimum de code pour faire passer le test
Refactor : améliorer le code sans changer le comportement (les tests protègent)

Ce que ça garantit : que chaque ligne de code existe pour satisfaire un besoin exprimé par un test. Que l’architecture émerge des contraintes de testabilité. Que le refactoring est sécurisé dès le premier jour.

Mais surtout : on voit le test échouer avant d’écrire le code. Ce n’est pas un détail. C’est la preuve que c’est bien l’implémentation qui l’a fait passer au vert - pas un test mal écrit qui passe dans le vide, pas un faux positif, pas un test qui ne teste rien.

Sa vraie force : le cycle Red/Green/Refactor force à penser en termes de comportements attendus, pas d’implémentations. Résultat : une architecture plus découplée, des interfaces mieux définies, et des tests qui testent des comportements - pas des méthodes.

Ce que chaque approche détecte

Situation Test After Test First TDD
Régressions futures
Bugs dans le code existant ❌ (biais)
Mauvaise conception Partiel
Code non testable
Cas limites oubliés Partiel

Comment choisir ?

TDD est l’approche la plus complète, surtout pour la logique métier. C’est une discipline, pas une technique - elle demande de la pratique, pas de la lecture. On ne “comprend” pas le TDD en théorie et on le réserve aux bons moments ; on le pratique jusqu’à ce que le Red/Green/Refactor devienne un réflexe, puis on ne revient pas en arrière.

Test First est légitime quand l’architecture est établie et les specs précises. On gagne la réflexion préalable sans la rigueur du cycle complet.

Test After n’a pas de cas d’usage qui lui soit propre. Tout ce qu’il apporte, Test First ou TDD l’apporte aussi - mieux. On fait du Test After parce qu’on ne sait pas encore faire autrement, ou parce que le contexte ne laisse pas le choix. C’est un point de départ, pas une destination.

Le vrai problème, c’est de faire du Test After en croyant faire du TDD.

En résumé

  • Test After : biais de confirmation, couplage à l’implémentation, fausse sécurité avec les agents IA. Pas de cas d’usage qui lui soit propre - on le fait faute de mieux.
  • Test First : force à penser le contrat avant l’implémentation. Nécessite une architecture connue.
  • TDD : les tests guident la conception. Meilleure détection des bugs et meilleure architecture - au prix d’un investissement initial.

La question n’est pas “est-ce que je dois faire du TDD ?” mais “est-ce que je sais ce que mon approche actuelle garantit - et ne garantit pas ?”


Le cycle TDD, les principes FIRST et les bonnes pratiques de tests sont au programme de mes formations Tests & Validation au CNAM Strasbourg.