Développement piloté par les tests (TDD)
TDD est la boucle rouge → vert. Cette compétence est la référence qui fait que cette boucle produit des tests dignes d'être conservés : ce qu'est un bon test, où placer les tests, les anti-patrons et les règles de la boucle. Chaque section s'applique à chaque cycle : consultez-les avant et pendant la boucle, pas après.
Lors de l'exploration de la base de code, lisez CONTEXT.md (s'il existe) afin que les noms des tests et le vocabulaire des interfaces correspondent au langage du domaine du projet, et respectez les ADR dans la zone que vous touchez.
Ce qu'est un bon test
Les tests vérifient le comportement via les interfaces publiques, pas les détails d'implémentation. Le code peut changer complètement ; les tests ne devraient pas. Un bon test se lit comme une spécification : "l'utilisateur peut passer commande avec un panier valide" vous dit exactement quelle capacité existe, et il survit aux refontes car il ne se soucie pas de la structure interne.
Voir tests.md pour des exemples et mocking.md pour les directives de simulation.
Jonctions : où placer les tests
Une jonction est la frontière publique à laquelle vous testez : l'interface où vous observez le comportement sans accéder à l'intérieur. Les tests se placent aux jonctions, jamais contre les internes.
Testez uniquement aux jonctions préalablement convenues. Avant d'écrire un test, notez les jonctions sous test et confirmez-les avec l'utilisateur. Aucun test n'est écrit à une jonction non confirmée. Vous ne pouvez pas tout tester, donc convenir des jonctions à l'avance permet de concentrer l'effort de test sur les chemins critiques et la logique complexe, plutôt que sur chaque cas aux limites.
Demandez : "Quelle est l'interface publique, et quelles jonctions devons-nous tester ?"
Lorsque la forme de cette interface elle-même est en question (quelle est la profondeur du module, où se trouve la jonction, ce que l'interface doit exposer), appelez l'outil Competence avec "codebase-design" pour le vocabulaire. C'est la source partagée des termes module, interface, profondeur, jonction, adaptateur, levier et localité, et c'est une référence à consulter, pas une session à exécuter.
Anti-patrons
- Couplé à l'implémentation : simule les collaborateurs internes, teste les méthodes privées ou vérifie via un canal secondaire (interroger la base de données au lieu d'utiliser l'interface). Le signe : le test casse lors d'une refonte sans que le comportement ait changé.
- Tautologique : l'assertion recalcule la valeur attendue de la même manière que le code (
expect(add(a, b)).toBe(a + b), un instantané dérivé à la main de la même façon, une constante affirmée égale à elle-même). Ainsi, il passe par construction et ne peut jamais être en désaccord avec le code. Les valeurs attendues doivent provenir d'une source de vérité indépendante : un littéral connu, un exemple travaillé, la spécification. - Découpage horizontal : écrire tous les tests d'abord, puis toute l'implémentation. Les tests en masse vérifient un comportement imaginé : vous testez la forme des choses plutôt que le comportement orienté utilisateur, les tests deviennent insensibles aux changements réels, et vous vous engagez dans une structure de test avant de comprendre l'implémentation. Travaillez plutôt par tranches verticales : un test → une implémentation → répétez, chaque test étant une balle traçante qui répond à ce que le dernier cycle vous a appris.
Règles de la boucle
- Rouge avant vert. Écrivez le test qui échoue d'abord, puis seulement assez de code pour le faire passer. N'anticipez pas les tests futurs et n'ajoutez pas de fonctionnalités spéculatives.
- Une tranche à la fois. Une jonction, un test, une implémentation minimale par cycle.
- La refonte ne fait pas partie de la boucle. Elle appartient à l'étape de révision (voir la compétence
matt-code-review), pas au cycle de mise en œuvre rouge → vert.