Je vous parlais récemment des tests unitaires. Je vous parlais entre autre de la difficulté d’imposer la discipline nécessaire à la réalisation de tests unitaires corrects et de leur maintien opérationnel.
Il existe une méthode de travail qui permet de forcer l’écriture des tests unitaires (tout au moins au début des développements). Il s’agit des développements guidés par les tests (ou Test Driven Development en anglais).
Cette méthode est toute simple à comprendre : Avant d’écrire un bout de code, on commence par écrire les tests qui vont vérifier la conformité du code.
Prenons l’exemple d’un code orienté objet. Imaginons que nous nous préparons à écrire une nouvelle classe.
- On modélise l’objet, donc on connait ses méthodes publiques. On sait quelles entrées doivent produire quels résultats.
- On écrit des tests pour vérifier les méthodes de l’objet.
- On écrit le squelette de l’objet, avec juste les déclarations des méthodes.
- On exécute les tests unitaires, qui tombent évidemment en échec.
- On écrit le code de l’objet, en vérifiant que les tests passent un à un.
L’avantage avec cette manière de faire, c’est qu’au moment où le code est écrit, on est quasi-certain qu’il est conforme au comportement qu’on attend de lui. Pour peu qu’on ait pris soin de lancer régulièrement les tests unitaires au cours du développement, le code est rapide à valider.
Par contre, il va sans dire que si le TDD permet d’avoir des tests unitaires corrects pour de nouveaux développements, le problème reste entier pour l’évolution de code existant. La vigilance habituelle reste donc de mise, pour que les tests ne prennent pas la poussière. Mais il est possible de respecter cette démarche pour toutes les évolutions de code : On commence par modifier les tests unitaires existants, ou les compléter ; puis on effectue les développements qui valideront ces tests.
Mon expérience
Le TDD est ce que je qualifierais de vraie fausse bonne idée. En fait, j’ai vu plusieurs fois le même cheminement intellectuel être suivi par des équipes qui mettaient en place cette méthode :
- Un nouveau développement est lancé. La volonté de « bien faire les choses » pousse à commencer par écrire les tests unitaires. => les TDD sont une bonne idée
- Des évolutions sont demandées et le donneur d’ordre est pressé. Il n’a pas envie de « perdre du temps » avec ces tests unitaires dont on lui rabat les oreilles. De son point de vue, ce n’est pas directement productif, donc c’est inutile. => les TDD sont une fausse bonne idée
- Ensuite, j’ai vu 2 scénarii possibles :
- Un bug apparaît. Pour accélérer le débuggage, on ressort les tests unitaires qui avaient été mis de côté. Et là, bingo, un des tests remonte une erreur, et on trouve très vite un bug de régression qui n’aurait pas été simple à trouver autrement. => les TDD sont une vraie
faussebonne idée - Des bugs apparaissent. Un seul développeur prend la peine de toujours commencer ses développements par l’écriture des tests unitaires ; et bizarrement, les bugs ne se situent jamais dans son code. Il ne perd pas de temps à traquer les bugs, il peut rester créatif et productif. => les TDD sont une vraie
faussebonne idée
- Un bug apparaît. Pour accélérer le débuggage, on ressort les tests unitaires qui avaient été mis de côté. Et là, bingo, un des tests remonte une erreur, et on trouve très vite un bug de régression qui n’aurait pas été simple à trouver autrement. => les TDD sont une vraie
Mais il ne faut pas se leurrer. Il est toujours assez difficile de discipliner des développeurs pour qu’ils écrivent leurs tests. Ils veulent toujours entamer le plus vite possible la partie la plus créative de leur boulot. Il faut alors rester ferme, et ne pas accepter de voir la moindre ligne de code écrite si les rapports de test (en échec, voir plus haut) ne sont pas présentés d’abord.
Je vous souffle une astuce : Ce que les développeurs détestent souvent encore plus que d’écrire des tests, c’est d’écrire des spécification techniques détaillées des développements qu’ils comptent faire. Ça leur semble pénible de réaliser les diagrammes UML de toutes leurs classes, avec la documentation complète de toutes les méthodes.
Alors il suffit de dire que les tests sont la spécification technique. Et c’est une bonne chose, car les tests unitaires valident un comportement, donc on peut considérer qu’ils décrivent le comportement attendu. Si au cours du développement on souhaite modifier quelque chose (changer les paramètres d’une méthode, ajouter des méthodes, etc.), il est assez facile d’adapter les tests en conséquence. En tout cas, les développeurs préféreront ça, plutôt que de devoir reprendre une spécification technique !
Parfois c’est meme le manager de l’équipe qui est pressé, qui veut qu’on rentre dans le sujet, et qui bypasse cette étape..
@Loic dans ce cas ce manager doit être lapidé puis crucifié