Test driven development (TDD) : le cycle, un exemple et nos conseils pour le réussir

· 15 min de lecture · Par Godefroy de Compreignac, CEO

Mis à jour le

Le TDD (Test Driven Development, ou développement piloté par les tests) est une méthode de développement logiciel où le développeur écrit un test automatisé avant le code qui le fait passer. Le développeur avance par cycles très courts de trois étapes : écrire un test qui échoue (rouge), écrire le code minimal qui le fait réussir (vert), puis nettoyer le code sans casser les tests (refactor). Kent Beck, l’un des créateurs de l’Extreme Programming, a formalisé la méthode au début des années 2000 dans son livre Test-Driven Development: By Example.

Chez Lonestone, on développe des applications web et mobiles sur mesure depuis 2014. Nos développeurs écrivent les tests en amont surtout pour livrer un code qu’une équipe pourra encore faire évoluer des années plus tard. Cet article explique le cycle du TDD, le montre sur un exemple en TypeScript, puis donne nos conseils pour l’installer dans une équipe de développement.

Comprendre les principes fondamentaux du Test Driven Development 

Cycle du TDD : Rouge, Vert, Refactor 

La phase "Rouge" marque le début du cycle. Le développeur commence par écrire un test qui définit une fonctionnalité ou une amélioration spécifique. Ce test est intentionnellement conçu pour échouer puisque le code n'existe bien sûr pas encore. Cet échec initial, signalé en rouge dans les outils de test, précise ce que le code doit accomplir. Cette étape force le développeur à réfléchir au comportement attendu avant même de commencer à coder la solution. 

Puis, la phase "Vert" commence. On écrit alors le code le plus simple possible pour réussir le test. L'idée n'est pas d'élaborer une solution élégante ni même optimisée, mais de satisfaire les exigences définies par le test. En allant à l’essentiel, on évite la sur-ingénierie et on est sûr que le code écrit répond précisément au besoin identifié. 

La phase "Refactor", intervient dans un troisième et dernier temps. C’est là qu’on peut améliorer le code, sans en modifier le comportement. Plus précisément, on va :  

  • Éliminer les duplications ;  

  • Simplifier la structure ;  

  • Optimiser les performances ;  

  • S'assurant que tous les tests continuent de réussir.  

C’est grâce à la phase “Refactor” qu’on obtient un code pérenne malgré les ajouts successifs de fonctionnalités. 

Ce cycle se répète pour chaque modification du produit, ce qui crée un processus de développement incrémental où chaque ajout est validé par des tests automatisés. 

Un exemple de TDD en TypeScript

Prenons une règle métier simple : une commande de plus de 100 € bénéficie de 10 % de remise. En TDD, on commence par le test, écrit ici avec Vitest :

import { describe, expect, it } from "vitest";
import { totalWithDiscount } from "./order";
describe("totalWithDiscount", () => {
it("applique 10 % de remise au-delà de 100 €", () => {
expect(totalWithDiscount(200)).toBe(180);
});
it("garde le prix plein jusqu’à 100 €", () => {
expect(totalWithDiscount(80)).toBe(80);
});
});

Le test échoue, puisque la fonction totalWithDiscount n’existe pas encore : c’est la phase rouge. On écrit ensuite le code le plus court qui fait passer les deux tests :

export function totalWithDiscount(amount: number): number {
return amount > 100 ? amount * 0.9 : amount;
}

Les tests passent au vert. Pendant la phase refactor, on sort le seuil et le taux dans des constantes nommées, puis on relance les tests pour vérifier que le comportement n’a pas changé. Une commande de 100 € pile doit rester au prix plein, mais aucun test ne le vérifie encore. On ajoute ce test. Il passe tout de suite, puisque le code compare avec >, mais il protège désormais ce cas limite contre une modification future.

Sur un vrai projet, un cycle dure de quelques secondes à quelques minutes. Les tests unitaires tournent en continu dans l’éditeur, ce qui demande une suite de tests rapide. Nos équipes développent en TypeScript de bout en bout. Le compilateur signale donc une partie des erreurs avant même le lancement des tests.

Les avantages du Test Driven Development 

Sur le plan technique, le test Driven Development donne lieu à une couverture de tests très large puisque chaque fonctionnalité est développée en réponse à un test spécifique. De fait, l'ensemble du code de production est couvert par des tests automatisés, on peut donc rapidement détecter les régressions lors des mises à jour suivantes, et ainsi considérablement diminuer les risques de bugs. 

Grâce au TDD, on a aussi beaucoup moins d’erreurs lors de la conception du produit. En effet, comme il faut toujours définir le comportement attendu avant d'implémenter une solution, on limite d’autant les ambiguïtés et les erreurs d’interprétation. Ainsi, les problèmes sont repérés tôt dans le cycle de développement, lorsqu’ils sont encore simples, rapides et pas trop chers à corriger. 

Autre grand point fort du TDD : c’est une approche tournée vers les besoins réels. Les tests représentent des cas d'utilisation concrets et des comportements attendus, ce qui maintient les efforts de développement concentrés sur les exigences fonctionnelles du projet plutôt que sur des points techniques abstraits. Le code ainsi produit apporte alors une véritable valeur aux utilisateurs finaux. 

Le TDD favorise également une conception modulaire et découplée. Pour être facilement testable, le code doit présenter une séparation claire des responsabilités et éviter au maximum les dépendances entre ses différentes parties. Il s’avère que ces caractéristiques contribuent également à une architecture logicielle plus saine et plus maintenable. 

Enfin, les tests décrivent précisément le comportement attendu du code et, contrairement à la documentation traditionnelle, sont constamment vérifiés lors de l'exécution des tests automatisés. Cette documentation par l'exemple reste ainsi toujours synchronisée avec le code actuel, offrant une ressource précieuse pour les nouveaux membres de l'équipe ou pour la maintenance future. 

Les tests écrits avant le code allègent aussi le travail de validation du client. Le client passe son temps sur les questions d’usage pendant la recette du projet, au lieu de signaler à nouveau une fonctionnalité qui a cessé de marcher entre deux versions.

Impact du Test First design sur la culture de développement 

Au-delà de ses indéniables avantages techniques, le Test Driven Development est aussi une méthodologie qui instaure un environnement où la qualité est intégrée dès le début du processus plutôt qu'ajoutée a posteriori. 

On apprend, avec le TDD, à considérer les tests non comme une tâche secondaire ou une contrainte, mais comme une partie intégrante et valorisante du travail de développement. Par conséquent : il n’y a plus à arbitrer en vitesse de développement et fiabilité puisque ce sont désormais deux faces d’une même pièce. 

Côté collaboration, les tests servent de langage commun pour discuter des fonctionnalités et des comportements attendus. Les sprint reviews deviennent plus objectives, se concentrant sur le respect des critères définis par les tests plutôt que sur des préférences stylistiques subjectives. On a donc plus d’échanges constructifs et moins de risques de conflit au sein de l'équipe. 

Même chose pour la communication avec les parties prenantes non techniques. Les tests peuvent être formulés en termes de comportements utilisateur et de résultats métier, ce qui permet de valider régulièrement, par les équipes marketing et commerciale que le développement reste aligné sur les attentes des clients et des utilisateurs. 

Enfin, le TDD encourage une culture d'amélioration continue. Le cycle "Rouge, Vert, Refactor" institutionnalise la pratique du refactoring régulier, et les équipes prennent alors l’habitude de constamment optimiser et simplifier leur code. 

Les limites du TDD

Le TDD rapporte le plus sur la logique métier : calculs, règles de gestion, droits d’accès, transformations de données. Il sert moins dans trois situations :

  • Un prototype jetable, dont le but est de tester une idée auprès d’utilisateurs en quelques jours.
  • Une interface encore en cours de conception, où la mise en page change à chaque atelier. Mieux vaut alors organiser des tests utilisateurs qu’écrire des tests unitaires.
  • Un code existant sans aucun test, qu’il faut couvrir par des tests de bout en bout avant de pouvoir le modifier en TDD.

Au démarrage, le TDD ralentit aussi l’équipe, le temps que le réflexe du test d’abord s’installe. Sur une application qui vit plusieurs années, ce temps se récupère sur la correction des régressions.

Comment appliquer le Test Driven Development : Nos conseils 

Les prérequis pour une mise en œuvre efficace du TDD 

Choisir les bons outils 

Ces outils doivent s'intégrer harmonieusement dans votre écosystème technologique existant tout en vous offrant les fonctionnalités nécessaires pour pratiquer efficacement le TDD : 

  • Pour vos projets Java : JUnit reste la référence avec son écosystème riche et mature. Vous pourrez le compléter par Mockito pour la création de mocks, facilitant l'isolation des composants lors de vos tests unitaires. 

  • Dans l'univers Python : PyTest vous donne accès à une syntaxe élégante et à des fonctionnalités comme le paramétrage des tests et les fixtures, rendant vos tests plus expressifs et maintenables. 

  • Pour vos applications JavaScript et TypeScript : Vitest s’impose sur les projets récents, car il lit le TypeScript sans configuration et relance immédiatement les tests concernés à chaque sauvegarde. Jest reste très répandu, notamment sur les applications React existantes, tandis que Mocha combiné à Chai pourra vous être utile dans des contextes nécessitant plus de flexibilité.

Parallèlement au framework, nous vous recommandons : 

  • L'installation d'extensions dans vos environnements de développement intégrés pour faciliter la génération et l'exécution des tests, ainsi que la visualisation immédiate des résultats. 

  • L'adoption d'outils d'analyse de couverture de code comme JaCoCo, Coverage.py ou Istanbul qui vous permettra de mesurer objectivement l'efficacité de votre démarche TDD et d'identifier les zones de votre code insuffisamment testées. 

Ces métriques, intégrées à vos pipelines d'intégration continue, vous fourniront un retour immédiat sur la qualité de vos tests et aideront vos équipes à rester aussi rigoureuses que nécessaire. 

Formation et sensibilisation des équipes 

Vous l’aurez compris, le Test Driven Development suscite un bouleversement des habitudes de travail de vos équipes, et il vous sera impossible de l’implémenter sans former ni sensibiliser les parties prenantes. 

L'organisation d'ateliers pratiques d’expérimentation du cycle TDD sur des exemples concrets, constitue une introduction efficace. Ces sessions permettent d'aborder les difficultés initiales dans un environnement contrôlé et de démontrer concrètement les bénéfices de l'approche.  

Pensez, si cela vous est possible, à faire animer ces ateliers par des mentors expérimentés dans la pratique du TDD car cela accélère considérablement la courbe d'apprentissage. En effet, ce type d’expert peut :  

  • Guider les équipes à travers les subtilités de la méthodologie ;  

  • Partager des stratégies éprouvées pour surmonter les obstacles communs ;  

  • Fournir des retours constructifs sur les tests écrits. 

Bien entendu, l’apprentissage et l’adaptation au TDD sont des processus qui prendront forcément du temps (et donc diminueront la productivité) alors pensez à prendre cette transition en compte lors du cadrage projet et de la roadmap produit. 

Nos astuces pour maximiser l'efficacité du test driven development 

Gérer les risques de sur-ingénierie 

L’écriture systématique de tests peut parfois conduire à une prolifération excessive de cas de test, ce qui veut dire une maintenance coûteuse pour très peu de valeur. Pour éviter cet écueil, concentrez vos efforts sur les fonctionnalités critiques du système. 

Pour savoir quels sont les composants qui bénéficieront le plus d'une couverture de test exhaustive, conduisez une analyse de risque.  

Autre outil dans votre besace pour prioriser les tests : les Test Driven Requirements : transformer les exigences fonctionnelles en scénarios de test avant même de commencer le développement. 

Gérer la complexité du code de test 

À mesure que la base de code s'étend, les tests peuvent devenir aussi complexes que le code de production lui-même, ce qui pose des problèmes de maintenance. Pour prévenir cette situation :   

  • Appliquez le principe DRY (Don't Repeat Yourself) particulièrement face à des configurations communes ou des vérifications répétitives, qui peuvent être factorisées dans des méthodes utilitaires ou des fixtures partagées.  

  • Rendez la structure des tests plus lisible et cohérente via des patterns de test tels que AAA (Arrange-Act-Assert) ou Given-When-Then. 

  • Utilisez des frameworks de mock afin d’isoler le composant testé de ses dépendances, et donc de clarifier l'intention du test et de rendre le composant plus solide face aux changements externes. 

Écrire les tests avant de confier le code à un agent IA

Les agents de codage IA ont rendu le TDD plus utile. Un agent produit vite du code plausible, mais il n’a aucun moyen de savoir seul si ce code fait ce que le métier attend. Quand le développeur écrit d’abord les tests, l’agent reçoit une spécification qu’il peut exécuter. L’agent code, lance les tests et corrige jusqu’à ce qu’ils passent au vert. Le développeur relit ensuite un code qui passe déjà les tests.

Faites écrire les tests par un développeur qui connaît les règles métier. Un agent qui écrit à la fois le code et ses tests a tendance à valider ce qu’il vient de produire, erreurs comprises. Nous séparons de la même façon celui qui produit et celui qui vérifie pour construire des agents IA fiables : l’IA propose, puis un contrôle déterministe accepte ou rejette sa proposition.

L'importance de la refactorisation continue au sein du process 

On est obligé d’insister sur l’importance de cette troisième phase du cycle TDD, car bien trop souvent elle se retrouve négligée sous la pression des délais. Pourtant, sans elle, impossible d’avoir un code de qualité sur le long terme. 

C’est pourquoi, la refactorisation doit être pratiquée systématiquement, tant sur le code de production que sur les tests eux-mêmes. Les moindres "code smells", méthodes trop longues, duplications ou couplages excessifs doivent être traités dès leur apparition, avant qu'ils ne s'ancrent profondément dans l'architecture. 

C’est là qu’entre en jeu l'automatisation des tests dans les pipelines d'intégration continue : en garantissant l'exécution systématique de tous les tests à chaque modification, elle offre un filet de sécurité qui permet de restructurer le code avec confiance. Cette confiance est essentielle pour encourager l'amélioration continue du code, plutôt que l'accumulation d’une dette technique qui, à terme, freinera l'évolution du produit. 

Ne négligez pas non plus les test reviews car elles permettent de partager les bonnes pratiques, d'identifier les patterns émergents et d'assurer la cohérence de l'approche TDD au sein de l'équipe. 

Enfin, le maintien d'une test suite rapide vous aidera aussi à préserver la dynamique du TDD. Cette rapidité peut être obtenue en séparant les tests unitaires légers des tests d'intégration plus lourds, et en utilisant judicieusement les mocks pour éviter les dépendances coûteuses. 

Certes, la transition vers la philosophie du "test d'abord, code ensuite" demande un investissement assez conséquent en temps et en formation, mais le retour sur investissement se manifeste à terme par une dette technique réduite et une meilleure vitesse de développement. 

Lonestone a développé des produits sur mesure pour plus de 200 clients, avec une équipe d’ingénieurs qui ont pour la plupart entre 10 et 25 ans d’expérience. Pour faire développer une application web sur mesure testée et maintenable, contactez-nous.

FAQ

Questions fréquentes

C’est quoi le TDD ?

Le TDD (Test Driven Development, ou développement piloté par les tests) est une méthode de développement logiciel où le développeur écrit un test automatisé avant le code qui doit le faire passer. Il travaille par cycles courts de trois étapes : écrire un test qui échoue (rouge), écrire le code minimal qui le fait réussir (vert), puis améliorer le code sans casser les tests (refactor). Kent Beck, l’un des créateurs de l’Extreme Programming, a formalisé la méthode au début des années 2000. Le TDD est une méthode de travail qui se pratique avec n’importe quel outil de test, comme Vitest ou Jest en TypeScript, JUnit en Java ou PyTest en Python.

Que signifie le deuxième D dans TDD ?

Le deuxième « D » de TDD signifie « Development » (développement). Le nom complet, Test Driven Development, veut dire que les tests pilotent le développement : ils sont écrits avant le code et guident sa conception comme son écriture. Le TDD est donc une méthode de conception autant qu’une pratique de test.

Quelle est la différence entre TDD, BDD et ATDD ?

Le TDD (Test Driven Development) part de tests unitaires écrits par les développeurs, dans le langage de programmation de l’application. Le BDD (Behavior Driven Development) décrit le comportement attendu du point de vue métier, dans un langage naturel structuré (souvent Gherkin et sa syntaxe « Given-When-Then »), que les product owners et analystes métier peuvent lire et rédiger. L’ATDD (Acceptance Test Driven Development) fait écrire les tests d’acceptation par le client, les testeurs et les développeurs ensemble, avant le développement d’une fonctionnalité. Les trois se combinent souvent : l’ATDD ou le BDD fixent ce que la fonctionnalité doit faire, puis le TDD guide l’écriture du code. Les tests d’acceptation écrits en ATDD sont aussi repris pendant la recette du projet.

Le TDD ralentit-il le développement ?

Le TDD ralentit l’équipe pendant les premières semaines, le temps que les développeurs prennent le réflexe d’écrire le test d’abord. Ensuite, le temps passé à écrire les tests se récupère sur la correction des bugs et des régressions, surtout sur une application maintenue pendant plusieurs années. Sur un prototype jetable, le gain est plus faible : beaucoup d’équipes y réservent le TDD à la logique métier. Un code testé limite aussi l’accumulation de dette technique.

Lonestone conçoit et développe vos produits numériques

On discute de votre projet ?

Échange gratuit et sans engagement, directement avec un expert du sujet. Devis sous 48h.

Contacter l'équipe
de Lonestone