Tester ou non, d'un point de vue technique

Déterminez ce que vous devez tester et ce que vous pouvez exclure.

L'article précédent expliquait les principes de base des scénarios de test et leur contenu. Cet article approfondit la création de scénarios de test d'un point de vue technique, en détaillant ce qu'il faut inclure dans chaque test et ce qu'il faut éviter. En résumé, vous apprendrez la réponse à de vieilles questions de type "Ce qu'il faut tester" et "Ce qu'il ne faut pas tester".

Ce qu'il faut tester ou non.

Consignes et modèles généraux

Il est important de noter que des modèles et des points spécifiques sont essentiels, que vous meniez des tests unitaires, d'intégration ou de bout en bout. Ces principes peuvent et doivent être appliqués à ces deux types de tests, et constituent donc un bon point de départ.

Pragmatiques

Lorsqu'il s'agit d'écrire des tests, l'une des choses les plus importantes à retenir est de rester simple. Il est important de tenir compte de la capacité du cerveau. Le code de production principal occupe beaucoup d'espace, ce qui laisse peu de place à la complexité. Cela est particulièrement vrai pour les tests.

Si l'espace disponible est limité, vous risquez d'être plus détendu dans vos tests. C'est pourquoi il est crucial de donner la priorité à la simplicité des tests. Les bonnes pratiques en matière de test JavaScript de Yoni Goldberg soulignent l'importance de la règle d'or : votre test doit ressembler à un assistant et non à une formule mathématique complexe. En d'autres termes, vous devez être en mesure de comprendre l'intention de votre test au premier coup d'œil.

Ne rendez pas les tests complexes, ils ne devraient pas avoir cette expérience.

Optez pour la simplicité dans tous les types de tests, quelle que soit leur complexité. En fait, plus un test est complexe, plus il est important de le simplifier. L'une des méthodes pour y parvenir est d'utiliser une conception de test plate, dans laquelle les tests sont simplifiés au maximum et de ne tester que ce qui est nécessaire. Cela signifie que chaque test ne doit contenir qu'un seul scénario de test, qui doit être axé sur une fonctionnalité ou une fonctionnalité spécifique.

Pensez-y de ce point de vue: il doit être facile d'identifier ce qui s'est mal passé lors de la lecture d'un test ayant échoué. C'est pourquoi il est important de proposer des tests simples et faciles à comprendre. Cela vous permet d'identifier et de résoudre rapidement les problèmes lorsqu'ils surviennent.

Testez ce qui en vaut la peine

La conception de tests plats favorise également l'attention et permet de s'assurer que vos tests sont pertinents. N'oubliez pas que vous ne devez pas créer de tests uniquement à des fins de couverture. Ils doivent toujours avoir un but.

Ne testez pas 
tout ce dont vous avez besoin.

Ne pas tester les détails de l'implémentation

L'un des problèmes courants des tests est qu'ils sont souvent conçus pour tester les détails de l'implémentation, tels que l'utilisation de sélecteurs dans les composants ou les tests de bout en bout. Les détails d'implémentation font référence à des éléments que les utilisateurs de votre code ne peuvent généralement pas utiliser, voir ni même connaître. Cela peut entraîner deux problèmes majeurs lors des tests: les faux négatifs et les faux positifs.

Des faux négatifs se produisent lorsqu'un test échoue, même si le code testé est correct. Cela peut se produire lorsque les détails de l'implémentation changent en raison d'une refactorisation du code de l'application. En revanche, des faux positifs se produisent lorsqu'un test réussit, même si le code testé est incorrect.

Une solution à ce problème consiste à prendre en compte les différents types d'utilisateurs dont vous disposez. Les utilisateurs finaux et les développeurs peuvent adopter une approche différente et interagir avec le code différemment. Lors de la planification des tests, il est essentiel de prendre en compte ce que les utilisateurs verront ou avec lesquels interagir, et de faire en sorte que les tests dépendent de ces éléments plutôt que des détails de l'implémentation.

Par exemple, en choisissant les sélecteurs les moins susceptibles de changer, vous pouvez rendre les tests plus fiables: les attributs de données plutôt que les sélecteurs CSS. Pour en savoir plus, consultez Kent C. article de Dodds sur ce sujet, mais sachez qu'il sera publié ultérieurement.

Manquer: ne perdez pas le contrôle

La simulation est un concept général utilisé dans les tests unitaires et parfois dans les tests d'intégration. Cela implique de créer des données ou des composants factices pour simuler des dépendances qui ont un contrôle total sur l'application. Cela permet d'isoler les tests.

Utiliser des simulations dans vos tests peut améliorer la prévisibilité, la séparation des tâches et les performances. Par ailleurs, si un test nécessite une intervention humaine (validation de votre passeport, par exemple), vous devez le dissimuler à l'aide d'une simulation. Pour toutes ces raisons, les simulations sont un outil précieux à prendre en compte.

En même temps, la simulation peut affecter la précision du test, car il s’agit d’une simulation et non de l’expérience utilisateur réelle. Vous devez donc être prudent lorsque vous utilisez des simulations et des bouchons.

Devez-vous simuler des tests de bout en bout ?

En général, non. Cependant, se moquer peut parfois s'avérer utile, alors ne l'excluons pas complètement.

Imaginez le scénario suivant: vous écrivez un test pour une fonctionnalité impliquant un service de paiement tiers. Vous vous trouvez dans un environnement de bac à sable qu'ils ont fourni, ce qui signifie qu'aucune transaction réelle n'a lieu. Malheureusement, le bac à sable fonctionne mal, ce qui entraîne l'échec de vos tests. La correction doit être effectuée par le fournisseur de services de paiement. Vous pouvez simplement attendre que le problème soit résolu par le fournisseur.

Dans ce cas, il peut être plus avantageux de réduire la dépendance aux services que vous ne pouvez pas contrôler. Il est toujours conseillé d'utiliser la simulation avec précaution lors des tests d'intégration ou de bout en bout, car cela diminue le niveau de confiance de vos tests.

Spécificités du test: choses à faire et à ne pas faire

Donc, dans l'ensemble, que contient un test ? Existe-t-il des différences entre les types de tests ? Examinons de plus près certains aspects spécifiques adaptés aux principaux types de tests.

Qu'est-ce qui doit être un bon test unitaire ?

Un test unitaire idéal et efficace doit:

  • Concentrez-vous sur des aspects spécifiques.
  • Fonctionner de manière indépendante.
  • Exploitez des scénarios à petite échelle.
  • Utilisez des noms descriptifs.
  • Suivez le modèle AAA, le cas échéant.
  • Garantissez une couverture de test complète.
À faire ✅ Pas ❌
Faites en sorte que les tests soient aussi petits que possible. Testez une chose par scénario de test. Écrivez des tests sur de grandes unités.
Isolez toujours vos tests et simulez des choses dont vous avez besoin, en dehors de votre unité. Incluez d'autres composants ou services.
Faites en sorte que les tests restent indépendants. Appuyez-vous sur des tests antérieurs ou partagez des données de test.
Abordez différents scénarios et parcours. Limitez-vous au maximum aux tests positifs ou négatifs.
Utilisez des titres descriptifs pour voir immédiatement de quoi il s'agit. Test par nom de fonction uniquement, n'étant pas assez descriptif au final: testBuildFoo() ou testGetId().
Cherchez une bonne couverture de code ou un plus large éventail de scénarios de test, en particulier à ce stade. Effectuez des tests de toutes les classes jusqu'au niveau de la base de données (E/S).

Qu'est-ce qui doit être un test d'intégration efficace ?

Un test d'intégration idéal partage également certains critères avec les tests unitaires. Cependant, il y a quelques points supplémentaires que vous devez prendre en compte. Un bon test d'intégration doit:

  • Simuler des interactions entre les composants
  • Couvrez des scénarios du monde réel et utilisez des simulations ou des bouchons.
  • Tenez compte des performances.
À faire ✅ Pas ❌
Testez les points d'intégration: vérifiez que chaque bloc fonctionne correctement lorsqu'il est intégré les uns aux autres. Les tests unitaires vous permettent de tester chaque unité de manière isolée.
Testez des scénarios réels: utilisez des données de test issues de données réelles. Utilisez des données de test répétitives générées automatiquement ou d'autres données qui ne reflètent pas des cas d'utilisation réels.
Utilisez des simulations et des bouchons pour les dépendances externes afin de garder le contrôle sur l'ensemble de votre test. créer des dépendances sur des services tiers, comme des requêtes réseau adressées à des services externes ;
Appliquez une routine de nettoyage avant et après chaque test. Si vous oubliez d'utiliser des mesures de nettoyage dans vos tests, cela peut entraîner des échecs ou des faux positifs en raison d'un manque d'isolation du test.

Qu'est-ce qui doit être un bon test de bout en bout ?

Un test complet de bout en bout doit:

  • dupliquer les interactions utilisateur ;
  • Incluez les scénarios vitaux.
  • s'étendent sur plusieurs couches ;
  • Gérez les opérations asynchrones.
  • Vérifiez les résultats.
  • Tenez compte des performances.
À faire ✅ Pas ❌
Utilisez des raccourcis basés sur les API. En savoir plus Utilisez les interactions de l'interface utilisateur pour chaque étape, y compris le hook beforeEach.
Appliquez une routine de nettoyage avant chaque test. Prenez encore plus de soin de l'isolation des tests que lors des tests unitaires et d'intégration, car le risque d'effets secondaires est plus élevé. Oublier de nettoyer après chaque test. Si vous ne nettoyez pas l'état, les données ou les effets secondaires restants, ils auront une incidence sur les autres tests exécutés ultérieurement.
Considérez les tests de bout en bout comme des tests système. Vous devez donc tester l'ensemble de la pile d'applications. Les tests unitaires vous permettent de tester chaque unité de manière isolée.
N'utilisez pas ou peu de simulation pendant le test. Réfléchissez bien avant de simuler des dépendances externes. Appuyez-vous fortement sur les simulations.
Tenez compte des performances et de la charge de travail en ne testant pas trop de scénarios volumineux dans le même test, par exemple. Abordez des workflows volumineux sans utiliser de raccourcis.