Développement Piloté par les Tests
Philosophie
Principe fondamental : Les tests doivent vérifier le comportement via les interfaces publiques, pas les détails d'implémentation. Le code peut changer complètement ; les tests ne doivent pas.
Les bons tests sont de style intégration : ils exercent de vrais chemins de code via les APIs publiques. Ils décrivent ce que le système fait, pas comment il le fait. Un bon test se lit comme une spécification – « l'utilisateur peut finaliser l'achat avec un panier valide » vous dit exactement quelle capacité existe. Ces tests survivent aux refactorisations car ils ne se soucient pas de la structure interne.
Les mauvais tests sont couplés à l'implémentation. Ils mockent les collaborateurs internes, testent des méthodes privées, ou vérifient par des moyens externes (comme interroger directement une base de données au lieu d'utiliser l'interface). Le signal d'alerte : votre test casse quand vous refactorisez, mais le comportement n'a pas changé. Si vous renommez une fonction interne et les tests échouent, ces tests testaient l'implémentation, pas le comportement.
Voir tests.md pour des exemples et mocking.md pour les directives sur le mocking.
Anti-pattern : Tranches Horizontales
NE RÉDIGEZ PAS tous les tests en premier, puis toute l'implémentation. C'est le « découpage horizontal » – traiter RED comme « écrire tous les tests » et GREEN comme « écrire tout le code ».
Cela produit des tests pourris :
- Les tests écrits en masse testent le comportement imaginé, pas le comportement réel
- Vous finissez par tester la forme des choses (structures de données, signatures de fonction) plutôt que le comportement vu par l'utilisateur
- Les tests deviennent insensibles aux vrais changements – ils passent quand le comportement casse, échouent quand le comportement est correct
- Vous outrepassez votre visibilité, vous engageant sur la structure des tests avant de comprendre l'implémentation
Approche correcte : Tranches verticales via balles traçantes. Un test → une implémentation → répétez. Chaque test répond à ce que vous avez appris du cycle précédent. Parce que vous venez d'écrire le code, vous savez exactement quel comportement importe et comment le vérifier.
MAUVAIS (horizontal) :
RED : test1, test2, test3, test4, test5
GREEN : impl1, impl2, impl3, impl4, impl5
BON (vertical) :
RED→GREEN : test1→impl1
RED→GREEN : test2→impl2
RED→GREEN : test3→impl3
...
Flux de Travail
1. Planification
Avant d'écrire du code :
- [ ] Confirmez avec l'utilisateur quels changements d'interface sont nécessaires
- [ ] Confirmez avec l'utilisateur quels comportements tester (priorisez)
- [ ] Identifiez les opportunités pour les modules profonds (petite interface, implémentation profonde)
- [ ] Concevez les interfaces pour la testabilité
- [ ] Listez les comportements à tester (pas les étapes d'implémentation)
- [ ] Obtenez l'approbation de l'utilisateur sur le plan
Posez la question : « À quoi devrait ressembler l'interface publique ? Quels comportements sont les plus importants à tester ? »
Vous ne pouvez pas tester tout. Confirmez avec l'utilisateur exactement quels comportements importent le plus. Concentrez l'effort de test sur les chemins critiques et la logique complexe, pas sur chaque cas limite possible.
2. Balle Traçante
Écrivez UN test qui confirme UNE seule chose sur le système :
RED : Écrivez le test pour le premier comportement → le test échoue
GREEN : Écrivez le code minimal pour passer → le test passe
C'est votre balle traçante – cela prouve que le chemin fonctionne de bout en bout.
3. Boucle Incrémentale
Pour chaque comportement restant :
RED : Écrivez le test suivant → échoue
GREEN : Code minimal pour passer → passe
Règles :
- Un test à la fois
- Juste assez de code pour passer le test actuel
- N'anticipez pas les tests futurs
- Gardez les tests focalisés sur le comportement observable
4. Refactorisation
Après que tous les tests passent, cherchez les candidats à refactoriser :
- [ ] Extrayez la duplication
- [ ] Approfondissez les modules (déplacez la complexité derrière des interfaces simples)
- [ ] Appliquez les principes SOLID où naturel
- [ ] Considérez ce que le nouveau code révèle sur le code existant
- [ ] Lancez les tests après chaque étape de refactorisation
Ne refactorisez jamais en RED. Arrivez à GREEN en premier.
Checklist Par Cycle
[ ] Le test décrit le comportement, pas l'implémentation
[ ] Le test utilise uniquement l'interface publique
[ ] Le test survivrait à une refactorisation interne
[ ] Le code est minimal pour ce test
[ ] Aucune fonctionnalité spéculative ajoutée