Vous moquez-vous des tests?

Par Bruno Barrette

Je me suis récemment « entretenu » avec le moi d’il y a plusieurs années, et nous en sommes arrivés à parler de tests unitaires. À cette époque, je me moquais des tests unitaires. Aujourd’hui, je m’en moque encore, mais de façon différente. Malgré les années passées, plusieurs des questions soulevées au cours de cette conversation sont encore d’actualité. Voulez-vous savoir comment celle-ci s’est déroulée? La voici, agrémentée d’extraits de code pour bien montrer mon cheminement…

Tu sais, tu devrais commencer tout de suite à mettre un peu plus l’accent sur les tests. Ce n’est pas juste une mode, cela va rester et crois-moi, c’est beaucoup plus important que tu peux le penser.

Je m’en moque des tests unitaires! Nous avons une équipe d’assurance qualité qui s’occupe de vérifier que nos applications fonctionnent.

Mais combien de fois est-ce que cela revient dans ta cour pour des « petits bogues »? Les tests unitaires auraient permis d’éviter cela, et l’équipe d’assurance qualité aurait pu se concentrer à vérifier le fonctionnement de l’application, et non voir si elle est brisée ou non.

Mais Bruno, c’est compliqué d’écrire des tests unitaires. Comment est-ce que je peux tester une fonction comme celle-ci?

test_1

Effectivement, tester une fonction comme celle-là, c’est un défi, parce qu’elle en fait beaucoup plus qu’elle devrait. La fonction crée ou met à jour un client, calcule le prix selon les taxes, et finalement sauvegarde la facture. Malgré qu’elle soit nécessaire dans le processus, toute cette logique n’a pas sa place ici. Tu pourrais déplacer ce qui concerne le client et les taxes dans leur propre classe, pour que chacune s’occupe d’une seule chose. Cela nous permettrait de respecter le principe SOLID de responsabilité unique qui dit qu’une classe ne devrait avoir qu’une seule responsabilité. De cette manière, pour ce qui est de tester cette méthode, on pourra se concentrer à vérifier qu’elle fait bien son travail, c’est-à-dire orchestrer le tout.

J’ai suivi ta recommandation. La logique pour créer ou mettre à jour le client est encapsulée dans sa classe, et j’ai maintenant une classe pour calculer mon prix. Par contre je ne vois toujours pas comment cela peut m’aider pour mes tests, je n’ai pas de contrôle sur ces objets à l’intérieur de ma méthode… Qu’en penses-tu ?

Test_2

Tout à fait d’accord avec toi, ce n’était que la première étape. Nous allons parler d’un autre principe SOLID, celui de l’inversion de dépendance. Le problème actuel, qui est probablement la principale raison pour laquelle tu as de la difficulté à tester, c’est que ta classe dépend de ces autres classes pour fonctionner. Donc, si plutôt que de dépendre de ces classes, tu dépendais d’interfaces? Tout ce dont ta classe aurait besoin, c’est de recevoir ces interfaces, dans le constructeur par exemple, et c’est l’appelant de celle-ci qui s’occuperait de créer les objets qui implémentent ces interfaces.

Bon, d’accord. J’ai fait un peu de « refactoring ». Mes classes sont maintenant des instances d’interfaces qui sont passées dans le constructeur de ma classe. Mais je dois quand même les créer pour tester ma méthode, alors si tu veux mon avis, j’ai juste déplacé le problème…

Test_3

Nous arrivons à la partie intéressante : les « mocks ». En gros, ces objets sont des simulateurs de comportement pour un objet donné. Nous pouvons donc dire à notre simulateur comment nous voulons qu’il se comporte, histoire de nous permettre de tester autre chose en fonction de ce comportement. Si nous reprenons ton exemple, cela peut donc nous permettre de simuler un retour de la base de données pour un nouveau client, comme s’il avait véritablement été créé.

Et comme nous contrôlons cette valeur, nous pouvons facilement vérifier que c’est bien celle-ci qui a été envoyée pour la sauvegarde de la facture. Par exemple, si tu voulais vérifier qu’il n’y a pas de calcul de taxes et de sauvegarde quand tu n’as pas de numéro de client, ton test pourrait ressembler à ceci :

test_4

Et en plus, maintenant que chacune de tes trois classes est bien isolée, tu vas voir que cela devient plutôt facile de tester leurs comportements individuellement.

Là je comprends! C’est super! Donc maintenant que je sais que tous mes morceaux fonctionnent bien, je peux être sûr que mon application va toujours bien fonctionner, n’est-ce pas? Plus besoin de faire de l’assurance qualité à ce propos?

Si seulement c’était aussi simple… Effectuer des tests unitaires sur des classes qui n’ont qu’une seule responsabilité, en simulant le comportement de leurs dépendances, est déjà un grand pas en avant. Mais cela ne fait que tester chaque composante. Imagine que le constructeur de ton automobile avait testé que les freins fonctionnent, que la pédale peut être enfoncée, mais pas le fonctionnement conjoint des deux éléments. Aurais-tu confiance en ta voiture? Et bien la réponse est la même du côté logiciel. Les tests d’intégration, qui sont essentiellement des tests automatisés pour des scénarios bien précis sur un environnement complet, et les tests manuels effectués par de vraies personnes, sont quand même nécessaires.

Je comprends, il faut donc continuer les tests manuels, mais quand même mettre l’accent sur les tests unitaires. Au moins, je sais maintenant comment attaquer le tout pour remanier mon code.

Nous avons parlé de ta méthode qui était déjà en place, que nous avons fait évoluer vers quelque chose d’un peu mieux structuré. D’ailleurs, ce qui est bien là-dedans, c’est que non seulement tu peux conduire tes tests unitaires plus facilement, mais en plus nous avons grandement amélioré la structure de ton code en fonction de principes fondamentaux de programmation. Et dis-toi que tu pourrais même faire cela pour du nouveau code, pas uniquement pour des choses existantes. Cela ne peut que t’aider dans ta carrière…

Et si nous avions plus de temps, nous pourrions parler de Test Driven Development, où tu écris carrément les tests avant d’écrire le code, et tu construis graduellement ton code fonctionnel au fur et à mesure que tu en as besoin au niveau des tests. Nous aurions aussi pu parler de « fakes » qui sont des classes concrètes qui renvoient des données précises sans suivre la vraie logique en arrière-plan, ou de « stubs » qui sont en quelque sorte l’ancienne manière de faire des mocks. Même si selon moi, il vaut mieux te concentrer sur les mocks.

Cela m’intéresse, mais effectivement il ne nous reste plus beaucoup de temps. Il serait bien de trouver un autre moment pour se parler. Et dis, tant qu’à parler avec mon futur moi, est-ce que tu pourrais me donner un petit scoop sur ce que je vais faire?

Cela risque de créer un problème avec le continuum espace-temps, mais pourquoi pas… Tu vas être coanimateur d’une chaîne sur YouTube, le Bracket Show, qui parle de questions reliées au domaine du développement logiciel. Mieux que ça, tu vas même faire un épisode sur ce dont nous venons de parler :

Autres articles qui pourraient vous intéresser

Qu’en est-il du développement de logiciels personnalisés à l’ère de l’informatique en nuage?

Fort à parier que vous ayez déjà adressé le cloud computing dans vos opérations quotidiennes. Savez-vous toutefois comment l’utilisation de ces services en ligne interagit avec le développement logiciel sur mesure? Approfondissons différents aspects de ce type de développement dans le contexte nuagique, ce qu’il permet, ses avantages, les défis à retenir et comment l’intégration...
comment les microservices aident à l'agilité

Microservice et Agiilité: les changements requis à l’ère numérique

L’ère numérique dans laquelle nous vivons présentement nécessite que nous apportions plusieurs changements dans nos manières de faire. Les entreprises qui perçoivent encore le développement logiciel comme un fardeau coûteux et non comme une force de frappe feront bientôt face à de nombreux défis importants. Pour surfer sur la vague technologique, les entreprises doivent pouvoir...
Explorer et innover au sein de notre laboratoire | Done Technologies

Hello World version entreprise

Le Hello World de base La meilleure façon d’apprendre un nouveau langage reste encore d’écrire l’application typique Hello World. Je ne compte plus le nombre de fois que j’ai commencé un nouveau projet par cette simple application. Par exemple, voici la plus simple application Hello World qui peut être faite en C# : Après avoir démarré...