Logo Parasoft

Bonnes pratiques de test unitaire: comment tirer le meilleur parti de votre automatisation de test

By Brian McGlauflin 14 mai 2019 8 min de lecture

Les tests unitaires aident les organisations à tester leurs charges de travail unité par unité, mais la question est de savoir quelles sont les meilleures façons d'aborder les tests unitaires ? Consultez cet article pour découvrir les meilleures pratiques en matière de tests unitaires.

Bonnes pratiques de test unitaire: comment tirer le meilleur parti de votre automatisation de test

By Brian McGlauflin 14 mai 2019 8 min de lecture

Les tests unitaires aident les organisations à tester leurs charges de travail unité par unité, mais la question est de savoir quelles sont les meilleures façons d'aborder les tests unitaires ? Consultez cet article pour découvrir les meilleures pratiques en matière de tests unitaires.

Les tests unitaires sont une pratique bien connue, mais il y a beaucoup de place à l'amélioration ! Ce poste couvre les meilleures pratiques de tests unitaires les plus efficaces, y compris des approches pour optimiser vos outils d'automatisation en cours de route. Nous discuterons également de la couverture du code, des dépendances fictives et des stratégies de test globales.

Qu'est-ce que le test unitaire?

Tests unitaires Il s'agit de la pratique consistant à tester des unités ou des composants individuels d'une application afin de valider le bon fonctionnement de chacun d'eux. En général, une unité représente une petite partie de l'application ; en Java, il s'agit souvent d'une classe unique. Notez que je ne définis pas ici le terme « unité » au sens strict, et qu'il appartient au développeur de déterminer la portée du code testé pour chaque test.

On oppose parfois le terme « test unitaire » à « test d'intégration » ou « test de bout en bout ». La différence réside dans le fait que, généralement, les tests unitaires servent à valider le comportement d'une unité testable, tandis que les tests d'intégration valident le comportement de plusieurs composants ensemble, ou de l'application dans son ensemble. Comme je l'ai dit, la définition d'une « unité » n'est pas stricte, et c'est à vous de décider de la portée de chaque test.

Pourquoi un test unitaire?

Les tests unitaires sont une technique éprouvée pour garantir la qualité des logiciels, avec de nombreux avantages. Voici (plus de) quelques bonnes raisons de faire un test unitaire:

  • Tests unitaires valide que chaque élément de votre logiciel fonctionne non seulement correctement aujourd'hui, mais continue de fonctionner à l'avenir, fournissant une base solide pour le développement futur.
  • Tests unitaires identifie les défauts à un stade précoce du processus de production, qui réduit les coûts de les fixer à des stades ultérieurs du cycle de développement.
  • Le code testé à l'unité est généralement plus sûr à refactoriser, puisque les tests peuvent être réexécutés rapidement pour valider que le comportement n'a pas changé.
  • L'écriture de tests unitaires oblige les développeurs à considérer dans quelle mesure le code de production est conçu pour le rendre adapté aux tests unitaires, et incite les développeurs à regarder leur code à partir d'un autre point de vue, les encourageant à prendre en compte les cas de coin et les conditions d'erreur dans leur mise en œuvre.
  • Inclure les tests unitaires dans le processus de révision du code peut révéler comment le code modifié ou nouveau est censé fonctionner. De plus, les examinateurs peuvent confirmer si les tests sont bons ou non.

Il est malheureux que trop souvent les développeurs n'écrivent pas du tout de tests unitaires, n'écrivent pas assez de tests ou ne les maintiennent pas. Je comprends - les tests unitaires peuvent parfois être difficiles à rédiger ou prendre du temps à maintenir. Parfois, il y a une date limite à respecter, et on a l'impression que la rédaction de tests nous fera manquer cette date limite. Mais ne pas écrire suffisamment de tests unitaires ou ne pas écrire de bons tests unitaires est un piège risqué dans lequel tomber.

Veuillez donc prendre en compte mes recommandations de bonnes pratiques suivantes sur comment écrire des tests propres, maintenables et automatisés qui vous offrent tous les avantages des tests unitaires, avec un minimum de temps et d'efforts.

Bonnes pratiques de test unitaire

Examinons quelques bonnes pratiques pour créer, exécuter et gérer des tests unitaires, afin d'obtenir les meilleurs résultats.

Les tests unitaires doivent être dignes de confiance

Le test doit échouer si le code est cassé et uniquement si le code est cassé. Si ce n'est pas le cas, nous ne pouvons pas faire confiance à ce que les résultats des tests nous disent.

Les tests unitaires doivent être maintenables et lisibles

Lorsque le code de production change, les tests doivent souvent être mis à jour et éventuellement débogués. Il doit donc être facile de lire et de comprendre le test, non seulement pour celui qui l'a écrit, mais aussi pour les autres développeurs. Organisez et nommez toujours vos tests pour plus de clarté et de lisibilité.

Les tests unitaires doivent vérifier un cas d'utilisation unique

Les bons tests valident une chose et une seule chose, ce qui signifie qu'en général, ils valident un seul cas d'utilisation. Les tests qui suivent cette meilleure pratique sont plus simples et plus compréhensibles, ce qui est bon pour la maintenabilité et le débogage. Les tests qui valident plus d'une chose peuvent facilement devenir complexes et prendre du temps à maintenir. Ne laissez pas cela arriver.

Une autre bonne pratique consiste à utiliser un nombre minimal d'assertions. Certaines personnes recommandent une seule assertion par test (cela peut être un peu trop restrictif); l'idée est de se concentrer sur la validation uniquement de ce qui est nécessaire pour le cas d'utilisation que vous testez.

Les tests unitaires doivent être isolés

Les tests doivent être exécutables sur n'importe quelle machine, dans n'importe quel ordre, sans affecter les uns les autres. Si possible, les tests ne doivent pas dépendre des facteurs environnementaux ou de l'état global / externe. Les tests qui ont ces dépendances sont plus difficiles à exécuter et généralement instables, ce qui les rend plus difficiles à déboguer et à corriger, et finit par coûter plus de temps qu'ils n'en économisent (voir digne de confiance, au dessus).

Il y a quelques années, Martin Fowler a écrit un article sur le code « solitaire » et « sociable » afin de décrire l'utilisation des dépendances dans le code applicatif et la manière dont les tests doivent être conçus en conséquence. Dans son article, le code « solitaire » ne dépend pas d'autres unités (il est plus autonome), tandis que le code « sociable » interagit avec d'autres composants. Si le code applicatif est solitaire, le test est simple… mais pour du code sociable testé, vous pouvez créer un test « solitaire » ou « sociable ». Un « test sociable » s'appuie sur des dépendances réelles pour valider le comportement, tandis qu'un « test solitaire » isole le code testé des dépendances. Vous pouvez utiliser des simulations pour isoler le code testé et créer un test « solitaire » pour le code « sociable ». Nous verrons comment procéder ci-dessous.
Image expliquant les tests unitaires sociables par rapport aux tests unitaires solitaires.
En général, l'utilisation de simulations pour les dépendances simplifie la vie des testeurs, car elle permet de générer des « tests isolés » pour du code sociable. Un test sociable pour du code complexe peut nécessiter une configuration importante et violer les principes d'isolement et de répétabilité. Mais comme la simulation est créée et configurée dans le test, elle est autonome et nous permet de mieux contrôler le comportement des dépendances. De plus, nous pouvons tester davantage de chemins de code. Par exemple, je peux renvoyer des valeurs personnalisées ou lever des exceptions depuis la simulation afin de couvrir des conditions limites ou d'erreur.

Les tests unitaires doivent être automatisés

Assurez-vous de exécuter des tests unitaires dans un processus automatisé. Cela peut être quotidien, ou toutes les heures, ou dans le cadre d'un processus d'intégration ou de livraison continue. Les rapports doivent être accessibles et examinés par tous les membres de l'équipe. En équipe, discutez des métriques qui vous intéressent : couverture du code, couverture du code modifié, nombre de tests en cours d'exécution, performances, etc.

Il y a beaucoup à apprendre en regardant ces chiffres, et un grand changement dans ces chiffres indique souvent des régressions qui peuvent être corrigées immédiatement.

Ebook: Améliorez les tests unitaires pour Java avec l'automatisation
Téléchargez le livre électronique

Utilisez un bon mélange de tests unitaires et d'intégration

Le livre de Michael Cohn, Réussir avec Agile: développement de logiciels avec Scrum, résout ce problème en utilisant un modèle de pyramide de test (voir l'illustration dans l'image ci-dessous). Il s'agit d'un modèle couramment utilisé pour décrire la répartition idéale des ressources de test. L'idée est qu'au fur et à mesure que vous montez dans la pyramide, les tests sont généralement plus complexes à construire, plus fragiles, plus lents à exécuter et plus lents à déboguer. Les niveaux inférieurs sont plus isolés et plus intégrés, plus rapides et plus simples à créer et à déboguer. Par conséquent, les tests unitaires automatisés devraient constituer la majeure partie de vos tests.

Image de la pyramide des tests avec la valeur des tests à chaque niveau ainsi que les complexités associées.

Les tests unitaires doivent valider tous les détails, les cas d'angle et les conditions aux limites, etc. Les tests de composants, d'intégration, d'interface utilisateur et fonctionnels doivent être utilisés avec plus de parcimonie, pour valider le comportement des API ou de l'application dans son ensemble. Les tests manuels doivent représenter un pourcentage minimal de la structure pyramidale globale, mais restent utiles pour l'acceptation de la version et les tests exploratoires. Ce modèle offre aux organisations un niveau élevé d'automatisation et de couverture des tests, afin qu'elles puissent intensifier leurs efforts de test et réduire au minimum les coûts associés à la création, à l'exécution et à la maintenance des tests.

Les tests unitaires doivent être exécutés dans le cadre d'une pratique de test organisée

Afin de garantir le succès de vos tests à tous les niveaux et de rendre le processus de test unitaire évolutif et durable, vous aurez besoin de pratiques supplémentaires en place. Tout d'abord, cela signifie écrire des tests unitaires au fur et à mesure que vous écrivez le code de votre application. Certaines organisations écrivent les tests avant le code de l'application (axé sur les tests or axé sur le comportement programmation). L'important est que les tests vont de pair avec le code de l'application. Les tests et le code de l'application devraient même être examinés ensemble dans le processus de révision du code. Les revues vous aident à comprendre le code en cours d'écriture (car elles peuvent voir le comportement attendu) et à améliorer les tests aussi!

L'écriture de tests avec du code ne concerne pas uniquement les nouveaux comportements ou les changements planifiés, elle est également essentielle pour les corrections de bogues. Chaque bogue que vous corrigez devrait avoir un test qui vérifie que le bogue est corrigé. Cela garantit que le bogue restera corrigé à l'avenir.

Adoptez une politique de tolérance zéro en cas d'échec des tests. Si votre équipe ignore les résultats des tests, pourquoi avoir des tests? Les échecs de test doivent indiquer de vrais problèmes… alors résolvez ces problèmes tout de suite, avant qu'ils ne gaspillent le temps du contrôle qualité, ou pire, qu'ils ne pénètrent dans le produit commercialisé.

Plus il faut de temps pour corriger les défaillances, plus elles coûteront cher à votre organisation en temps et en argent. Exécutez donc des tests pendant la refactorisation, juste avant de valider le code, et ne considérez pas une tâche comme terminée tant que les tests ne sont pas eux aussi réussis.

Enfin, des maintenir ces tests. Comme je l'ai déjà dit, si vous ne gardez pas ces tests à jour lorsque l'application change, ils perdent leur valeur. Surtout s'ils échouent, les tests échoués coûtent du temps et de l'argent à enquêter chaque fois qu'ils échouent. Refactorisez les tests selon vos besoins, lorsque le code change.

Comme vous pouvez le voir, maximiser vos retours sur argent et temps investi dans vos tests unitaires nécessite un certain investissement dans l'application des meilleures pratiques. Mais au final, les récompenses valent l'investissement initial.

Qu'en est-il de la couverture du code?

En général, la couverture du code est une mesure de la quantité de code de production exécutée pendant que votre tests automatisés sont en cours d'exécution. En exécutant une série de tests et en examinant couverture de code Grâce à ces données, vous pouvez vous faire une idée générale de la proportion de votre application qui est testée.

Il existe de nombreux types de couverture de code - les plus courants sont la couverture de ligne et la couverture de succursale. La plupart des outils se concentrent sur la couverture de ligne, qui vous indique simplement si une ligne spécifique a été couverte. Branch est plus granulaire, car il vous indique si chaque chemin à travers le code est couvert.

La couverture du code est une métrique importante, mais rappelez-vous que l'augmenter est un moyen d'arriver à une fin. C'est génial pour trouver des lacunes dans les tests, mais ce n'est pas la seule chose sur laquelle se concentrer. Veillez à ne pas dépenser trop d'efforts pour essayer d'atteindre une couverture à 100% - cela peut même ne pas être possible ou faisable, et vraiment la qualité de vos tests est la chose importante. Cela étant dit, atteindre au moins 60% de couverture pour vos projets est un bon point de départ, et 80% ou plus est un bon objectif à fixer. Évidemment, c'est à vous de décider quel devrait être cet objectif.

Il est également utile si vous disposez d'outils automatisés qui mesurent non seulement la couverture du code, mais également la quantité de code modifié couvert par les tests, car cela peut permettre de savoir si suffisamment de tests sont en cours d'écriture avec les modifications du code de production.

Voir ici un exemple de rapport de couverture de code du hub de reporting et d'analyse de Parasoft, que vous pouvez parcourir si vous utilisez Jtest Parasoft pour votre tests unitaires:

Exemple de rapport de couverture de Parasoft DTP.

Une autre chose à garder à l'esprit est que, lors de l'écriture de nouveaux tests, veillez à ne vous concentrer que sur la couverture de ligne, car des lignes de code uniques peuvent entraîner plusieurs chemins de code, alors assurez-vous que vos tests valident ces chemins de code. La couverture de ligne est un indicateur rapide utile, mais ce n'est pas la seule chose à rechercher.

Le moyen le plus évident d'augmenter la couverture est simplement d'ajouter plus de tests pour plus de chemins de code et plus de cas d'utilisation de la méthode testée. Un moyen efficace d'augmenter la couverture consiste à utiliser des tests paramétrés. Pour Junit4, il y avait la fonctionnalité paramétrée Junit4 intégrée et des bibliothèques tierces comme JUnitParams. JUnit3 a un paramétrage intégré.

Enfin, si vous ne suivez pas déjà la couverture des tests, je vous recommande vivement de commencer. Il existe de nombreux outils qui peuvent vous aider, comme Jtest Parasoft. Commencez par mesurer vos chiffres de couverture actuels, puis fixez-vous des objectifs où elle devrait être, comblez d'abord les lacunes importantes, puis travaillez à partir de là.

Résumé

Bien que les tests unitaires soient une technique éprouvée pour garantir la qualité des logiciels, ils sont toujours considérés comme un fardeau pour les développeurs et de nombreuses équipes ont encore du mal avec cela. Afin de tirer le meilleur parti des tests et des outils de test automatisés, les tests doivent être fiables, maintenables, lisibles, autonomes et utilisés pour vérifier un cas d'utilisation unique. L'automatisation est essentielle pour rendre les tests unitaires réalisables et évolutifs.

En outre, les équipes logicielles doivent mettre en pratique de bonnes techniques de test, telles que la rédaction et la révision des tests parallèlement au code d'application, la maintenance des tests et la garantie que les tests échoués sont suivis et corrigés immédiatement. L'adoption de ces meilleures pratiques de test unitaire peut rapidement améliorer les résultats de vos tests unitaires.

Apprenez à augmenter votre rendement des tests unitaires avec Parasoft Jtest.
Demandez une démo maintenant