L’article d’introduction débute en listant certaines différences entre ma vision en terme d’architecture applicative ou encore de rédaction des tests, que je peux avoir avec d’autres développeurs. À travers elles, j’évoque les difficultés qu’ils peuvent rencontrer à identifier précisément quoi tester et comment.
Deux phrases extraites de l’article de Ian Cooper ont été mises en avant :
Ces deux axes sont à mon sens essentiels. Nous allons essayer de les décortiquer un par un, à travers des exemples, pour en comprendre leur essence et en quoi ils sont si importants pour faciliter le quotidien de l’équipe de développement.
Ici, nous débuterons par le premier axe : “Le code issu d’un refactoring ne requiert pas de nouveaux tests” en illustrant ce qu’il implique dans l’écriture des tests.
Dans cette article : Un test peut en cacher un autre — Tests unitaires — P2, nous nous attardons davantage sur le second axe : “Je vous recommande d’utiliser ports/adaptateurs et d’écrire les tests en outside-in depuis le use case.”.
On va travailler avec un Kata qui sera la gestion d’un système de réservation de livres dans une librairie, dont les règles sont les suivantes :
NDR : le code est en TypeScript, qui propose un typage statique fort. Néanmoins, le code peut être transposé dans des langages comme JavaScript, Python ou PHP qui ont nativement un typage dynamique et faible pour certains.
Après plusieurs cycle TDD, les tests suivants ont émergé :
https://gist.github.com/mickaelw/07fa70b57b8df2a7d232be7bd7bd9056
Cela a permis de construire la méthode privée applyDiscount de la classe Basket.ts :
https://gist.github.com/mickaelw/8c3114a8592ed35aeca9bbd7c23a7e30
Ici, on pourrait y voir plusieurs violations :
Pour éviter ces deux violations on va remanier (r_efactoring_) le code pour arriver à une nouvelle possibilité d’implémentation (ce n’est pas la seule possible).
Nouvelle méthode applyDiscount de la classe Basket.ts :
https://gist.github.com/mickaelw/4bc3b4c8aa186af99e195d43c7e51173
https://gist.github.com/mickaelw/1be81c0344d007d00fce08d7f0967953
https://gist.github.com/mickaelw/0cb36222116fa457cde7ffd8804264ed
https://gist.github.com/mickaelw/84cd2d64e7fbb60c1a1e71c801b2037b
La suite de tests est restée inchangée, il y a aucun nouveau test pour vérifier les nouvelles classes créées via le refactoring. Elles sont forcément couvertes par ceux existants, dans le cas contraire les tests seraient devenus rouges.
Un TU doit tester unitairement un comportement/une intention utilisateur et non une implémentation possible. Le nom du TU doit également le refléter, ce qui permet d’avoir une documentation fonctionnelle.
De ce fait une classe ou un fichier de code de production n’équivaut pas à un fichier de tests unitaires.
Unitaire désigne une unité de comportement du système et non une unité de code.
Plusieurs symptômes peuvent indiquer quand nous sortons de cette conclusion :
Le dernier est certainement l’un des plus importants, car nous pratiquons TDD notamment pour avoir cette puissance pour refactorer la structure profonde du code de manière totalement sécurisée.
Résumé en une image :