Il y a presque autant de méthodes et paradigmes de développement
que de langages de programmation, mais certains méritent que
l'on s'y intéresse plus qu'à d'autres, tant leur apport au quotidien du développeur
est démontré. Le Test-Driven Development (développement guidé
par le test), ou TDD, est de ceux-ci. Nous l'avions d'ailleurs
déjà rapidement abordé lors de notre article sur le test logiciel, mais nous prenons ici le temps de l'étudier
plus avant.
Description
Une explication en quelques mots du TDD ? Cela pourrait être : "on écrit les
tests avant d'écrire le code qui est testé". Bien qu'existant
depuis de nombreuses années, les récents ouvrages sur l'eXtreme
Progamming (XP), dont les tests unitaires sont une pierre
angulaire, ont largement contribué à sa nouvelle popularité.
Le cycle habituel de développement, depuis une éternité,
est le suivant : "concevoir, programmer, tester, débuguer,
re-tester, re-débuguer, etc", trop souvent ad vitam eternam.
Le TDD propose d'inverser cette tendance, afin si possible
d'éliminer, ou au moins de réduire grandement, le cycle de test
et de débogage.
Pour ce faire, il place le test avant toute écriture de
code : après avoir conçu sur papier son application, le
développeur écrit un test pour, par exemple, une classe de
son application, est seulement après avoir terminé ce test,
écrit la classe qu'il teste. Le but n'est plus d'écrire
du code, mais d'écrire le code le plus simple possible capable
de passer le test. Plus globalement, cette méthode doit
amener le développeur à faire ressortir les fonctionnalités
réellement nécessaires à la classe, plutôt que celles qui
semble utiles selon lui.
Le principe
de cette méthode consiste à écrire chaque test un a un, avec
la classe qui l'accompagne. Une fois que la classe passe correctement
le test, on la teste avec les éléments qui s'y rapportent
(et leurs propres tests), puis on passe au test suivant (et
à la classe qu'il teste).
Il faut faire attention d'avancer pas à pas (ou plutôt, test/classe
à test/classe), et tester à chaque étape : ainsi, si un test
ne passe pas (provoque un échec), c'est que le code que l'on
vient d'écrire pose problème - on le modifie alors immédiatement
pour que la classe passe le test.
Si le test provoque une erreur plutôt qu'un échec, il faut
d'abord s'assurer que le test renvoie bien un échec dans un
cas choisi comme faux, puis re-tester - et modifier la classe
si l'erreur se produit toujours.
Et si un test est mal écrit ?
La solution la plus rapide consiste, après avoir écrit le
test, à écrire un bout de code qui fera forcément rater le
test. Si le test passe malgré tout, il faut le revoir.
Ce cycle porte l'appellation "red/green/refactor ". Les développeurs
qui utilisent des outils de test logiciels, comme JUnit, reçoivent
en réponse au lancement de leurs tests une réponse claire
: soit rouge (le teste ne passe pas), soit vert (le test passe).
Si c'est rouge, il faut remanier le code (refactor).
Quelques avantages du TDD
Cette méthode de programmation, loin d'être révolutionnaire
ni même nouvelle mais se révélant souvent extrêmement utile, offre
plusieurs avantages aux développeurs souhaitant être rigoureux
:
1) Les bugs sont trouvés plus vite : cela semble une
évidence, mais écrire une classe par rapport à un test permet
de s'assurer que la classe fait bien ce que l'on attend d'elle.
Par ailleurs, enchaîner développement du test/développement
de la classe/test permet de repérer aussi le code fautif,
plutôt que d'attendre la complétion de nombreuses classes
reliées entre elles et pouvant par leurs complexités additionnées
cacher un bogue pourtant simple.
Au fur et à mesure du développement, chaque classe dispose
de son propre test, et chaque test correspond à une classe
donnée. Un test qui échoue ne peut donc signifier une erreur
que dans une classe
2) Il oblige le développeur à prendre en compte le plus
de possibilités dans ses tests. Il est plus facile d'écrire
un test qui prenne en compte un grand nombre de possibilités,
que de concevoir du premier coup un code qui les prenne d'entrée
de jeu en compte. Le temps de développement se réduit ainsi.
3) Etant donné que le code est écrit pour être testé, le
développeur est incidemment obligé de mieux concevoir ses classes.
Le code en devient quasi-automatiquement plus propre,
plus lisible, plus facile à isoler et à modifier.
4) Les tests viennent habituellement à la fin de la phase
de développement, prennent du temps et n'apporte le plus souvent
que des mauvaises nouvelles. Commencer par écrire les tests
permet de les automatiser, donc de gagner du temps
sur
la phase de tests.
Notez bien que cela ne permet pas de repérer tous les bugs,
mais bien ceux issus de fautes d'inattention
et donc qui
font généralement perdre un temps mieux utilisé à résoudre
des bugs plus sérieux. Le TDD n'est évidemment pas
une formule magique qui élimine automatiquement tous
les bugs.
Comment s'y prendre
La méthode est donc d'inverser les principes acquis : on commence
par écrire, en quelque sorte, l'utilisateur de la classe.
Cela permet de définir ses besoins (plutôt que les besoins
de la classe), donc d'y répondre en adaptant la classe aux
besoins du test, ce de la manière la plus simple possible,
et en commençant par un code imparfait afin de s'assurer que
le test remarque les possibles erreurs (échec, et non erreur).
|
Forum |
|
Réagissez
dans les forums
de JDN Développeurs
|
Les grands projets comptent un grand nombre de classes, souvent
plus que ce qu'un développeur peut retenir. Il devient alors
nécessaire de tester le code de manière automatique, et c'est
là qu'interviennent des outils comme Ant
et JUnit.
Ant est un outil de compilation automatique, tandis que JUnit
est un framework de test automatique. Les deux combinés permettent
de lancer l'ensemble des tests créés, et si ceux-ci passent
avec succès, de compiler l'application automatiquement. Le
projet peut ainsi obtenir des "nightly-builds", compilation
réalisée pendant la nuit pour ne pas gêner le développement,
que l'on peut en théorie lancer, voire utiliser, afin de découvrir
des bugs moins automatiquement discernables.
Nous aborderons le coté pratique du test unitaire dans un
prochain tutoriel.
|