Types de tests automatisés

Les noms donnés à différents types de tests ont tendance à avoir des thèmes communs dans tous les codebases, mais ils n'ont pas de définitions particulièrement rigoureuses. Ce cours donne quelques consignes sur la signification de chaque type de test, mais d'autres ressources peuvent fournir des définitions différentes.

Les pages précédentes ont présenté des exemples de tests unitaires et de tests de composants (dans notre exemple, il s'agit d'un composant React). Nous pouvons placer ces deux éléments bas sur notre pyramide de test (ou une autre forme !), car ils sont peu complexes et rapides à exécuter, mais ils n'auront peut-être pas autant d'utilité qu'un test d'intégration plus complexe.

Voici quelques exemples de test de formes de stratégie: pyramide, diamant taille, cornet de glace, hexagone et trophée.
Une stratégie de test peut se présenter sous toutes les formes.

Types de tests courants

Tests unitaires

Les tests unitaires sont les plus petits de la portée. Ils ont tendance à être utilisés pour tester de petites parties du code, ou du code purement sans état, de manière presque mathématique: si je fournis au code les entrées X, Y et Z, sa sortie doit être A, B et C.

Le code avec des tests unitaires n'a normalement pas de dépendances externes, telles que l'extraction depuis un réseau ou l'utilisation implicite d'autres fonctions ou bibliothèques. Il s'agit d'un nœud d'arborescence de votre code que vous pouvez "découper" et tester seul.

Bien que les tests unitaires soient généralement rapides à écrire et à exécuter, il est toujours possible que les tests de petites unités de code ne fournissent pas d'informations utiles. Souvent, le manque d'interaction d'une unité de code avec un autre code signifie qu'il vaut mieux effectuer des tests à un niveau supérieur pour réduire les risques.

Tests des composants

Pour les développeurs Web, le nom "composant" est surchargé, ce qui signifie souvent qu'il s'agit d'un composant visible par l'utilisateur, tel qu'un composant React ou un composant Web. Sa définition plus générale est un fragment de travail testable, par exemple une classe avec des dépendances externes. Pour être testé efficacement, les dépendances de ce composant doivent être simulées ou ignorées.

Les pratiques modernes de développement Web étant fondées sur le concept de composant, les tests de composants constituent un moyen pratique d'envisager les tests. Par exemple, vous pouvez décider que chaque composant nécessite un test. Les tests de composants sont également faciles à suivre dans les contextes où un seul développeur ou une petite équipe revendique la propriété claire d'un composant. Cependant, il peut être difficile de simuler des dépendances complexes.

Tests d'intégration

Ils ont tendance à tester ensemble un petit groupe de composants, de modules, de sous-systèmes ou d'autres parties pertinentes de votre code pour s'assurer qu'ils fonctionnent correctement. C'est une définition très vague. Pour les développeurs Web, imaginez que le code que vous testez n'est pas la véritable version de production de votre site (ou même une version proche), mais qu'il connecte tout de même divers composants associés de votre système.

Cela peut même inclure des dépendances "réelles", telles qu'une base de données externe en mode test, plutôt qu'une simulation pure. Par exemple, au lieu d'indiquer que query() renverra toujours les deux mêmes entrées, votre test d'intégration peut confirmer qu'une base de données de test contient quelque chose. Les données elles-mêmes sont moins importantes, mais vous testez maintenant qu'une base de données peut être connectée et correctement interrogée.

Il est possible d'écrire des tests d'intégration relativement simples avec des implications étendues, qui peuvent être vérifiés à l'aide d'assertions, car une seule action connectée à différents composants peut entraîner une série d'effets mesurables. De ce fait, les tests d'intégration peuvent démontrer efficacement que votre système complexe s'exécutera comme prévu. Cependant, ils peuvent être difficiles à écrire et à gérer, et peuvent introduire une complexité inutile. Par exemple, l'écriture d'un FakeUserService pour un test d'intégration implique que ce test et le RealUserService doivent implémenter un UserService.

Tests de fumée

Ces tests doivent s'effectuer très rapidement et déterminer si votre codebase est dans un état raisonnable. En pratique, cela implique principalement d'effectuer des tests simples sur du code aux effets divers sur l'expérience.

Par exemple, dans une grande application Web connectée, cela peut garantir le bon fonctionnement du système de connexion et d'authentification, car sans cela, l'application est inutilisable et d'autres tests ne sont pas pertinents.

Les tests de fumée peuvent s'exécuter sous le script test de votre fichier package.json dans un codebase volumineux. Un test manuel peut également servir de sorte de test de fumée.

Tests de régression

Les tests de régression sont un type de test de fumée qui garantit que les fonctionnalités existantes continuent de fonctionner ou que les anciens bugs ne sont pas réintroduits après une nouvelle version ou d'autres développements de fonctionnalités.

Cela est lié au concept de développement piloté par les tests (TDD, Test-driven development). Les scénarios de test écrits pour déclencher explicitement un bug, puis utilisés pour s'assurer que le bug est corrigé, sont considérés comme des scénarios de test de régression, car leur existence doit empêcher le retour de ce même bug.

Les tests de régression peuvent toutefois poser problème sans solution optimale. Ce terme est souvent cité par les besoins des entreprises: à mesure que les fonctionnalités sont développées, il est important que les anciennes ne cessent de fonctionner. Un codebase bien testé devrait être capable de maintenir cela, mais les vrais codebases ne répondent pas toujours à cet idéal. Nous y reviendrons plus en détail dans les sections suivantes.

Tests visuels

Les tests visuels impliquent de prendre des captures d'écran ou des vidéos de l'état d'un site Web afin de vérifier un état correct connu (comme une capture d'écran précédente) par rapport à l'exécution du test en cours. De par sa nature, il nécessite l'exécution d'un navigateur réel afin qu'il puisse afficher le code HTML, CSS et d'autres parties du site Web.

Plutôt que de tester visuellement des tests de bout en bout qui exécutent l'ensemble de votre codebase, il peut être utile de créer des "habillages" HTML qui n'affichent que certains composants, en particulier dans différentes tailles d'écran, afin de déclencher des interfaces utilisateur réactives. Cette méthode est plus complexe que d'utiliser uniquement JSDOM ou des frameworks similaires.

L'échec des tests visuels peut être un bon indicateur d'autres types de dysfonctionnement. Cependant, les interfaces utilisateur complexes peuvent échouer aux tests visuels pour des raisons sans rapport avec les fonctionnalités que vous essayez de tester, telles que d'autres nouvelles fonctionnalités qui modifient l'apparence de l'interface utilisateur, ou même une nouvelle version de l'OS dont le rendu des emoji est différent de celui des versions précédentes.

Tests de bout en bout

Les tests de bout en bout se situent souvent au sommet de la pyramide des tests. Elles décrivent une interaction complète avec votre application ou votre site Web, peut-être axée sur une fonctionnalité spécifique, et s'exécutent généralement dans un navigateur contrôlé par un agent tel que WebdriverIO, Selenium ou Puppeteer, qui peut exécuter votre codebase plus ou moins comme il serait déployé en production (bien qu'ils soient souvent diffusés sur localhost).

En fonction de votre site, vous devrez peut-être vous connecter en tant qu'utilisateur test, effectuer des actions importantes et vérifier que l'état de votre site ou de votre système est correct. Nous couvrirons d'autres exemples de ce type de test dans d'autres sections, car ils peuvent être très puissants, mais parfois difficiles à gérer.

Certaines tactiques pour les simplifier peuvent inclure la réduction de leur portée ou la simulation de composants spécifiques, le cas échéant. Par exemple, si les utilisateurs doivent se connecter à votre site, mais que vous ne testez pas la fonctionnalité de connexion, vous pouvez définir un indicateur pour les environnements de test permettant au contrôleur de test d'agir en tant qu'utilisateur sans se connecter ni créer les cookies associés.

Bien que les tests de bout en bout puissent être très efficaces pour effectuer des tests sur de vastes sections transversales de votre codebase en une seule fois, ces tests à grande échelle risquent d'être irréguliers ou peu fiables en raison de leur dépendance aux systèmes externes. Ils peuvent également laisser beaucoup de données de test dans votre base de données si, par exemple, chaque test crée ou modifie une entrée. Avec l'accumulation de données restantes comme celle-ci, il peut être difficile de déterminer pourquoi un test a échoué.

Tests d'API

Les tests d'API peuvent consister à confirmer le comportement des API fournies par votre logiciel ou à accéder à des API réelles (éventuellement en direct) pour confirmer leur comportement. Dans tous les cas, cela tend à tester les abstractions entre les systèmes (comment ils communiqueront à terme entre eux) sans les intégrer réellement ensemble, comme dans un test d'intégration.

Ces tests peuvent constituer un précurseur de base des tests d'intégration, sans les frais généraux liés à l'exécution des systèmes entre lesquels vous testez les connexions. Cependant, les tests de systèmes réels peuvent être irréguliers.

Autres

Diverses approches de test peuvent être utiles en fonction de votre source. Voici quelques exemples intéressants:

  • Test manuel.
  • Les tests d'acceptation, un type de test manuel popularisé par Agile, confirment que le produit "répond aux besoins de l'utilisateur".
  • Le test de chaos consiste à saisir des données aléatoires pour voir ce qui se passe et s'assurer qu'un site ne plante pas si des données incorrectes sont saisies.
  • Les tests de défaillance simulent intentionnellement les défaillances de systèmes complexes, telles que les défaillances de réseau, pour s'assurer que le code soumis aux tests répond de manière contrôlée.
  • Les tests de compilation confirment que les artefacts de compilation d'un codebase peuvent être générés en vérifiant leur existence ou leur contenu. Ce type de test peut être utile pour vérifier la sortie d'un CMS complexe.

Couverture de code

Vous pouvez mesurer le pourcentage de votre code qui est testé par des tests automatisés et le signaler en tant que statistique au fil du temps. Nous vous déconseillons de viser une couverture de code de 100 %, car cela peut entraîner des frais généraux inutiles, ainsi que des tests simplistes ou mal conçus qui ne couvrent pas les principaux cas d'utilisation en profondeur.

La couverture elle-même peut également être un outil utile lorsque vous écrivez ou travaillez sur des tests, en particulier des tests d'intégration. En affichant un pourcentage ou une répartition ligne par ligne du code testé par un seul test, vous pouvez obtenir des informations sur ce qui manque ou sur ce qui peut être testé ensuite.

Ressources

Testez vos connaissances

Parmi les éléments suivants, lesquels sont des types de tests connus ?

Tests visuels
Test du chaos
Tests d'incendie
Peut-être si vous construisez un logiciel pour un service de pompiers.
Tests de différenciation
Tests de résistance
Nous n'en avons pas parlé ici, mais les tests de contrainte ou de charge sont un type de test des systèmes de production visant à vérifier qu'ils peuvent accepter une grande quantité de trafic. Elle est davantage associée à une conception de système de grande envergure qu'à des tests de codebases plus classiques.