De nombreux ingénieurs pensent que pour chaque méthode publique de chaque classe, ils doivent créer un « test unitaire » correspondant.
C’est faux. Ce n’était pas ce que beaucoup entendaient par « unité » lorsque le terme « test unitaire » a été utilisé pour la première fois.
Le problème avec cette définition des tests unitaires est que vous ne vous concentrez plus sur le comportement de test, mais sur la mise en œuvre.
Les tests que vous écrivez sont étroitement liés à la conception sous-jacente de votre code. Le design est en constante évolution. Vous devez désormais non seulement refactoriser les conceptions de votre code de production, mais également modifier vos tests !
En d’autres termes, vos tests devraient vous aider avec la refactorisation, en donnant confiance, mais au lieu de cela, cela ne fait que vous faire travailler plus dur et cela ne donne aucune confiance que les choses fonctionnent toujours correctement.
Je ne mentionnerai même pas le faux enfer par souci de concision (veuillez Google à ce sujet).
Mais au lieu d’abandonner la refactorisation ou les tests unitaires, il vous suffit de vous libérer de la définition erronée de « tests unitaires ». Concentrez-vous sur les comportements de test !
Au lieu d’écrire des tests unitaires pour chaque méthode publique de chaque classe, écrivez des tests unitaires pour chaque composant (c’est-à-dire utilisateur, produit, commande, etc.), couvrant chaque comportement de chaque composant et se concentrant sur l’interface publique de l’unité.
Pour y parvenir, vous devrez apprendre à structurer correctement votre code. Veuillez ne pas packager votre code par soucis techniques (contrôleurs, services, référentiels, etc.). Les développeurs seniors structurent leur code par domaine.
Couverture de code
Les lignes de code couvertes ne signifient pas qu’il est prêt pour la vraie vie. Il ne vous dira pas que vous étiez censé vérifier cette chaîne pour une barre oblique et la couper ou vous demander de vérifier les valeurs nulles.
Les rapports de couverture de code sont dangereux. Cela a tendance à détourner l’attention des cas d’utilisation qui devraient guider le processus de développement logiciel.
Si nous ne sommes pas autorisés à livrer lorsque la couverture du code est inférieure à 80%, nous ajouterons de plus en plus de tests triviaux sans grande valeur pour garantir la qualité ou apporter de la confiance lors du refactoring.
La couverture du code n’a rien à voir avec la qualité du code, qui a été prouvée statistiquement
Kent Beck (Auteur du livre TDD By Example) a répondu à la question de savoir combien de tests unitaires un système devrait avoir :
« Je suis payé pour du code qui fonctionne, pas pour des tests, donc ma philosophie est de tester le moins possible pour atteindre un niveau de confiance donné… »
Martin Fowler a demandé si un système peut avoir trop de tests, en disant :
« Pouvez-vous tester trop ? Bien sûr que vous le pouvez. Vous testez trop si vous pouvez supprimer des tests tout en en ayant encore assez. »
Cela ne veut pas dire que la couverture n’a pas de valeur. Comme le souligne Martin Fowler, c’est un bon moyen d’identifier le code non testé.
Mettre en œuvre une stratégie d’automatisation des tests
Les tests dans ces courtes itérations Agiles nécessitent une approche « décaler à gauche ». Ce changement à gauche dans le processus de développement agile signifie que les tests commencent beaucoup plus tôt dans le cycle de vie de l’application. Par conséquent, les développeurs doivent posséder l’assurance qualité, ce qui signifie que les développeurs écrivent, exécutent et maintiennent des tests pour le code qu’ils produisent ; il encourage tous les membres de l’équipe à s’engager à livrer rapidement des produits de haute qualité au client.
Maintenant que nous savons qui doit écrire les tests, examinons ma stratégie de test recommandée.
Les tests devraient commencer « dans le petit » et progresser vers les tests « dans le grand » ; par conséquent, nous devrions nous concentrer davantage sur les tests unitaires. Le but est de tester chaque partie du logiciel en la séparant. Il vérifie que le composant correspond au comportement attendu. Rappelez-vous, l’unité ici n’est pas la classe.
Vient ensuite le test du module. L’objectif est de tester différentes parties du système en combinaison pour évaluer s’ils fonctionnent correctement ensemble. En testant les unités en groupes, tout défaut dans la façon dont elles interagissent peut être identifié.
Et enfin, des tests de bout en bout. Dans cette phase de test, différents modules logiciels sont combinés et testés en groupe pour s’assurer que le système intégré fonctionne correctement.
Les plans de test E2E couvrent généralement des histoires au niveau des utilisateurs telles que :
- « Un utilisateur peut se connecter. »
- « Un utilisateur peut faire un dépôt. »
- « Un utilisateur peut voir son solde. »
Conclusion
Il est essentiel de comprendre que nous devrions écrire des tests pour permettre aux équipes d’avancer rapidement. Le code évolue constamment et les développeurs doivent se sentir en confiance en ajoutant de nouvelles fonctionnalités et en améliorant continuellement le code existant.
Certaines idées ici peuvent être controversées, et vous n’avez pas besoin d’être d’accord avec moi, mais les dirigeants doivent remettre en question le statu quo et rechercher de nouvelles façons de faire les choses.
N’acceptez pas aveuglément les modes, les mythes, les autorités et les vérités établies. Remettez tout en question, accumulez de l’expérience et jugez par vous-même.
Exemple
Si vous souhaitez en savoir plus sur la façon d’écrire des tests efficaces, vous pouvez consulter mon projet open source où je montre comment structurer le code pour permettre la création de tests unitaires significatifs.