Présentation du test automatisé

Effectué

Dans cette unité, vous découvrirez les avantages offerts par les tests automatisés et les types de tests que vous pouvez effectuer. Vous découvrirez également ce qui fait un bon test et quelques-uns des outils de test disponibles.

Présentation du test automatisé

Le test automatisé utilise des logiciels pour exécuter votre code et comparer les résultats réels aux résultats attendus. Comparez cela avec des tests exploratoires ou manuels, où généralement un humain suit les instructions d’un plan de test pour vérifier que le logiciel fonctionne comme prévu.

Un test manuel a ses avantages. Mais à mesure qu’augmente la taille de votre base de code, le fait de tester toutes les fonctionnalités manuellement (y compris les cas limites) peut s’avérer répétitif, fastidieux et sujet aux erreurs. Les tests automatisés peuvent aider à éliminer une partie de ce fardeau et permettre aux testeurs manuels de se concentrer sur ce qu’ils font le mieux : garantir que vos utilisateurs auront une expérience positive avec votre logiciel.

Pyramide de tests

En matière de tests automatisés, il est courant de séparer les tests en différentes couches. Mike Cohn propose ce concept, connu sous le nom de pyramide de tests, dans son livre Succeeding with Agile.

Diagram showing the test pyramid. The pyramid shows the unit test layer marked with callout 1, and UI layer tests marked with callout 2.

Bien qu’il s’agisse d’une version simpliste du modèle de Cohn, le concept montre que vous concentrez la plupart de vos efforts sur l’écriture de tests qui vérifient les niveaux fondamentaux de votre logiciel (marqués « 1 » dans la pyramide), comme les fonctions, les classes et les méthodes. Vous concentrez progressivement moins d’effort à mesure que les fonctionnalités sont combinées, par exemple au niveau de la couche de l’interface utilisateur (marquée « 2 » dans la pyramide). L’idée est que si vous pouvez vérifier que chaque composant du niveau inférieur fonctionne comme prévu de façon isolée, les tests aux niveaux supérieurs doivent seulement vérifier que plusieurs composants fonctionnent ensemble pour obtenir le résultat attendu.

Quand dois-je écrire des tests ?

La réponse dépend principalement de vos besoins et de votre expérience dans l’écriture de tests.

Il n’est jamais trop tard pour commencer à ajouter des tests pour du code que vous avez déjà écrit et déployé. Cela est particulièrement vrai pour les fonctionnalités qui sont souvent endommagées ou qui nécessitent le plus d’effort de la part de votre équipe de test.

Quand vous établissez un lien entre les tests et les pipelines d’intégration continue et de livraison continue, vous allez entendre parler de deux concepts : le test continu et le décalage à gauche.

Le concept de test continu fait référence au fait que les tests sont exécutés au début du processus de développement à chaque fois qu’une modification est effectuée dans le pipeline. Le concept de décalage à gauche fait référence à la prise en compte des tests et de la qualité des logiciels plus tôt dans le processus de développement.

Par exemple, les développeurs ajoutent souvent des cas de test quand ils développent une fonctionnalité et ils exécutent la suite de tests complète avant d’envoyer la modification au pipeline. Cette approche contribue à garantir que la fonctionnalité qu’ils créent se comporte comme prévu et ne perturbe pas les fonctionnalités existantes.

Voici une brève vidéo où Abel Wang, Cloud Advocate chez Microsoft, vous explique comment maintenir la qualité de votre plan DevOps.

Demander à Abel

Le décalage à gauche nécessite souvent que les testeurs s’impliquent dans le processus de conception, avant même que du code soit écrit pour la fonctionnalité. Comparez cela au modèle de « transfert » où l’équipe de test ne se voit présenter de nouvelles fonctionnalités à tester qu’une fois le logiciel conçu et écrit. Un bogue détecté en retard dans le processus peut affecter le calendrier de livraison de l’équipe, et les bogues peuvent être découverts des semaines ou même des mois après la création initiale de la fonctionnalité par le développeur.

Le compromis

Le test automatisé s’accompagne de compromis. Bien que les tests automatisés permettent aux testeurs de consacrer l’essentiel de leur temps à la vérification de l’expérience de l’utilisateur final, les développeurs peuvent être amenés à consacrer plus de temps à la rédaction et à la mise à jour de leur code de test.

Cependant, le point important concernant les tests automatisés est que les testeurs ne reçoivent que du code de la meilleure qualité; du code dont il a été établi qu’il fonctionnait comme prévu. Ainsi, les développeurs peuvent récupérer une partie de leur temps en traitant moins de bogues ou en évitant de devoir réécrire du code en raison d’un cas limite qu’ils n’avaient pas pris en compte à l’origine.

Avantages supplémentaires

La documentation et la possibilité de refactoriser votre code plus facilement sont deux autres avantages des tests automatisés.

Documentation

Les plans de test manuel peuvent servir de type de documentation concernant le comportement que doit avoir le logiciel et la raison d’être de certaines fonctionnalités.

Les tests automatisés peuvent servir le même objectif. Le code des tests automatisés utilise souvent un format contrôlable de visu. Le jeu d’entrées que vous fournissez représente les valeurs que vos utilisateurs sont susceptibles d’entrer. Chaque résultat associé spécifie le résultat que l’utilisateur doit attendre.

En fait, de nombreux développeurs suivent la méthode du développement piloté par les tests (TDD) en écrivant leur code de test avant d’implémenter une nouvelle fonctionnalité. L’idée consiste à écrire un ensemble de tests, souvent appelé spécifications, qui échouent au départ. Ensuite, le développeur écrit de façon incrémentielle du code pour implémenter la fonctionnalité jusqu’à ce que tous les tests réussissent. Non seulement les spécifications documentent les exigences, mais le processus TDD aide à faire en sorte que seule la quantité de code nécessaire soit écrite pour implémenter la fonctionnalité.

Refactorisation

Supposons que vous avez une grande base de code que vous souhaitez refactoriser pour accélérer l’exécution de certaines parties. Comment savez-vous que vos efforts de refactorisation n’endommageront pas certaines parties de votre application ?

Les tests automatisés servent de type de contrat. Autrement dit, vous spécifiez les entrées et les résultats attendus. Quand vous avez un ensemble de tests qui réussissent, vous êtes mieux à même d’expérimenter et de refactoriser votre code. Quand vous apportez une modification, il vous suffit d’exécuter vos tests et de vérifier qu’ils continuent de réussir. Une fois que vous avez atteint vos objectifs de refactorisation, vous pouvez envoyer votre modification au pipeline de build afin que tout le monde puisse en bénéficier, mais avec un risque moindre de perturber quelque chose.

Quels sont les types de test automatisé ?

Il existe de nombreux types de test automatisé. Chacun test a un objectif distinct. Par exemple, vous pouvez exécuter des tests de sécurité pour vérifier que seuls les utilisateurs autorisés peuvent accéder à un élément logiciel ou à l’une de ses fonctionnalités.

Quand nous mentionnons l’intégration continue et le pipeline de build, nous faisons généralement référence aux tests de développement. Le test de développement fait référence à des tests que vous pouvez exécuter avant de déployer l’application sur un environnement de test ou de production.

Par exemple, le test lint, qui est une forme d’analyse statique du code, examine votre code source pour vérifier s’il est conforme au guide de style de votre équipe. Le code qui est mis en forme de façon cohérente est plus facile à lire et à maintenir.

Dans ce module, vous allez utiliser des tests unitaires et des tests de couverture du code.

Les tests unitaires vérifient les composants essentiels de votre programme ou bibliothèque, tels qu’une fonction ou méthode particulière. Vous spécifiez une ou plusieurs entrées ainsi que les résultats attendus. Test Runner exécute chaque test et vérifie si les résultats attendus et réels sont identiques.

Par exemple, supposons que vous avez une fonction qui effectue une opération arithmétique incluant la division. Vous pouvez spécifier quelques valeurs que les utilisateurs sont susceptibles d’entrer ainsi que des valeurs de cas limite, comme que 0 et -1. Si une certaine entrée produit une erreur ou une exception, vous pouvez vérifier que la fonction produit la même erreur.

Le test de couverture du code calcule le pourcentage de votre code qui est couvert par vos tests unitaires. Les tests de couverture du code peuvent inclure des branches conditionnelles dans votre code pour faire en sorte qu’une fonction soit couverte.

Plus votre pourcentage de couverture du code est élevé, moins élevée est la probabilité que vous détectiez ultérieurement un bogue dans un code qui n’a pas été entièrement testé. Vous n’avez pas besoin d’atteindre une couverture du code de 100 %. En réalité, lorsque vous démarrez, vous allez constater un faible pourcentage, mais cela vous donne un point de départ à partir duquel vous pouvez ajouter des tests qui couvrent le code problématique ou fréquemment utilisé.

Les tests unitaires doivent être isolés

Quand vous vous initiez aux tests unitaires, vous pouvez être amené à entendre des termes comme simulations, stubs et injection de dépendances.

Rappelez-vous qu’un test unitaire doit vérifier une fonction ou méthode spécifique, et non pas la façon dont plusieurs composants interagissent. Mais si vous avez une fonction qui appelle une base de données ou un serveur web, comment gérer cela ?

En plus de rompre l’isolation, un appel à un service externe peut aussi entraîner des ralentissements. Si le serveur de base de données ou le serveur web tombe en panne ou est indisponible, l’appel peut aussi interrompre votre série de tests.

En utilisant des techniques comme l’injection de dépendances et la simulation, vous pouvez créer des composants qui imitent cette fonctionnalité externe. Vous aurez un exemple plus loin dans ce module.

Par la suite, vous pouvez exécuter des tests d’intégration pour vérifier que votre application fonctionne correctement avec un serveur de base de données ou web réel.

Qu’est-ce qui caractérise un bon test ?

Vous serez davantage en mesure d’identifier un bon test en gagnant en expérience via l’écriture de vos propres tests et la lecture de tests écrits par d’autres personnes. Voici quelques conseils pour commencer :

  • Ne testez pas juste pour tester : vos tests doivent servir un objectif qui est bien plus qu’un élément à barrer dans une check-list. Écrivez des tests qui vérifient que votre code critique fonctionne comme prévu et qu’il ne perturbe pas des fonctionnalités existantes.
  • Faites des tests courts : les tests doivent s’effectuer aussi vite que possible, en particulier ceux qui se font pendant les phases de développement et de génération. Si les tests sont exécutés chaque fois qu’une modification progresse dans le pipeline, ils ne doivent pas être un goulot d’étranglement.
  • Vérifiez que vos tests sont répétables : les séries de tests doivent produire chaque fois les mêmes résultats, qu’ils soient exécutés sur votre ordinateur, sur celui d’un collègue ou dans le pipeline de build.
  • Gardez vos tests bien ciblés : une idée fausse couramment véhiculée est que les tests sont conçus pour couvrir le code écrit par d’autres personnes. Normalement, vos tests doivent couvrir seulement votre code. Par exemple, si vous utilisez une bibliothèque de graphiques open source dans votre projet, vous n’avez pas besoin de la tester.
  • Choisissez le bon niveau de précision : par exemple, si vous effectuez des tests unitaires, un test individuel ne doit pas combiner ou tester plusieurs fonctions ou méthodes. Testez chaque fonction séparément et écrivez ultérieurement des tests d’intégration qui vérifient que plusieurs composants interagissent correctement.

Quels sont les types d’outils de test disponibles ?

Les outils de test que vous utilisez dépendent du type d’application que vous créez et du type des tests que vous voulez effectuer. Par exemple, vous pouvez utiliser Selenium pour effectuer des tests d’interface utilisateur sur de nombreux types de navigateurs web et de systèmes d’exploitation.

Quel que soit le langage de votre application, de nombreux outils de test sont à votre disposition.

Par exemple, pour les applications Java, vous pouvez choisir Checkstyle pour effectuer des tests lint et JUnit pour effectuer des tests unitaires.

Dans ce module, nous allons utiliser NUnit pour les tests unitaires, car il est populaire auprès de la communauté .NET.

Vérifiez vos connaissances

1.

D’après la pyramide de tests, où devez-vous passer la majeure partie de votre temps dédié à l’exécution des tests ?

2.

À quoi le décalage à gauche fait-il référence ?

3.

Quelle est la meilleure pratique de test parmi les suivantes ?