GLO-4002 - Site du cours 2023

Temps estimé: 45 minutes

Exercice: monter une stratégie de test

Pour cet exercice, nous allons utiliser une page de création de compte.

Voici un wireframe de cette page :

Image de l'app

Pour les fins de l'exercice, imaginons que nous avons un front-end très minimaliste. Le JavaScript de la page ne fait que prendre les 3 champs et les envoyer au back-end via un API rest. Il n'y a aucune validation faite en JavaScript. Selon la réponse du back-end, 2 choses peuvent se produire :

  1. Un succès, alors on redirige l'utilisateur sur la page https://website.com/login
  2. Une erreur, alors on affiche le message d'erreur à l'endroit prévu.

Voici les critères d'acceptations qui ont été écrits par le PO:

CritèreDéfinition
COS 1Si un des champs est manquant, l'erreur "Tous les champs sont requis" est affichée
COS 2Si le username est déjà pris, alors l'erreur "Ce username est déjà pris" est affichée
COS 3Si les 2 password ne correspondent pas, l'erreur "Les passwords ne concordent pas` est affichée
COS 4Si le mot de passe ne contient pas au minimum 8 caractères dont 1 symbole, alors on affiche "Password invalid"
COS 5Après la création du compte (succès seulement), l'utilisateur est redirigé vers https://website.com/login
COS 6Le compte est persisté *
COS 7Un courriel est envoyé à admin@website.com lorsqu'un compte est créé, avec le username choisit

* Ce critère n'est pas excellent, idéalement "L'utilisateur peut s'authentifier avec son nouveau compte" serait mieux, mais afin de réduire la portée de cet exercice, on va considérer le COS 6 comme correct.

La communication entre le front-end et le back-end se fait via un API rest :

POST /accounts
Content-Type: application/json

{
    "username": "??",
    "password": "??",
    "password_confirmation: "??"
}

Et la réponse est la suivante :

{
  "success": true | false,
  "error_message": null | string
}

Question 1

Pour chacun des COS ci-haut, nous voudrions avoir un ou plusieurs tests fonctionnels pour tester ces critères.

À quel niveau placeriez-vous chacun d'entre eux afin de respecter la pyramide de tests?

  1. Manuel (qui ne fait pas partie de la pyramide, mais qui est tout de même nécessaire)
  2. Large
  3. Medium
  4. Small

Il y a plus de tests que de COS ici, et c'est voulu! C'est pour permettre un boulonnage des tests, ceci est expliqué plus bas.

  • Valider que les champs sont présents (COS 1) peut se faire via un test small ou medium (si on prend un framework de validation)
  • Valider que l'erreur est affichée (COS 1 à 4), peut importe l'erreur, peut être un test small en javascript
  • Valider que le back-end retourne les bonnes réponses d'API peut être un test médium (COS 1 à 4)
    • Il est possible de faire cela en démarrant le serveur, mais en lui injectant une doublure du service applicatif, afin de contrôler les réponses
  • Valider que le formulaire est bien envoyé peut être un test small en JavaScript (qui s'exécute sans le back-end) (COS 1 à 4)
  • Valider que le username n'est pas pris (COS 2) peut être un test small
  • Valider que le password et la confirmation concorde peut être au niveau small (COS 3)
  • Valider que le password respecte les règles de sécurité peut être un test small (COS 4)
  • Valider la redirection peut être un test small au front-end (COS 5)
  • Valider que le compte est persisté peut être un test medium entre le repository et la BD (en mémoire ou non) (COS 6)
  • Valider que le email est bien écrit (avec le username dedans) peut être un test small (valide seulement le contenu) (COS 7)
  • Valider l'envoie du email pourrait être un test manuel dans bien des cas, si nous n'avons pas d'autres façons. Il existe des outils qui permettent de faire des tests medium pour l'envoie d'email, mais ce n'est pas toujours possible.

Total:

  • Manuel: 1
  • Large: 0
  • Medium: 2
  • Small: 8

Le problème avec cette solution qui minimise tous les types de tests, c'est qu'aucun ne fait le bout-en-bout. Nous n'avons rien qui permet de tester la "colle" entre les morceaux (la configuration, l'injection des dépendances, le bon format de la base de données, intégration entre le front-end et le back-end, etc). Dans une application vraiment simple, ces tests pourraient être inutiles, mais présumons ici que nous sommes dans une application plus complexe et qu'il serait souhaitable de faire ce test.

Une stratégie possible, afin de ne pas dupliquer de tests, pourrait être d'en "élire" un qui sera exécuté à plus haut niveau. Il est typiquement plus simple de prendre le "happy path" pour cela. Ici, on pourrait dire que le test qui sert à valider qu'il y a une redirection après la création du compte serait un test large. Dans ce cas, celui-ci se ferait en démarrant le serveur et en passant par le front-end afin de faire une boucle complète. Nous aurions donc au total :

  • Manuel: 1
  • Large: 1
  • Medium: 2
  • Small: 7

Ce qui correspond bien aux ratios demandés par la pyramide de test.

Notez que le "boulonnage" des tests est la clé ici. Puisque j'ai un test en javascript qui s'assure que le formulaire est soumis correctement, et que j'ai un test medium qui s'assure que l'API répond correctement au contrat, alors je n'ai pas besoin d'avoir un test large pour chacun des COS.

Il s'agit d'un pattern fréquent: je valide que l'utilisateur du contrat l'utilise correctement, et ensuite que l'exécuteur du contrat remplit sa tâche correctement. De cette façon, chaque côté du contrat peut changer comme bon lui semble sans affecter tous les tests, ce qui ajoute de la flexibilité et rend les tests moins fragiles.

Question 2

Nous avons maintenant répondus aux critères d'acceptation demandés par le client. Par contre, nous n'avons pas fini!

Seriez-vous réellement confiant de livrer en production, les yeux fermés, à 16h un vendredi soir avec les tests ci-haut?

Bien que nos tests respectent la pyramide, nous n'avons pas vraiment regardé le quadrant de tests :

quadrant

Pour chacun des 4 quadrants, écrivez les autres tests qui seraient pertinents de faire.

Q1

Pour le premier quadrant, il s'agit simplement de tous les tests unitaires qu'un développeur ferait normalement. Certains seront doublement considérés comment étant des tests d'acceptations également (ceux de la question 1), mais c'est bien correct.

D'autres exemples seraient un test de contexte (s'assurer que l'app démarre et lit les bonnes configurations, par exemple).

Certains auteurs ajouteraient également ici des tests d'API (format, protocol, etc).

Q2

Les tests de la question 1 vont ici, donc nous avons pas mal couvert ce quadrant!

Q3

Notre page étant une création de compte très standard, il n'est pas vraiment pertinent de faire des tests utilisateurs. Une démo au PO serait sûrement suffisant!

Dans certains cas nous pourrions ici vouloir mesurer des métriques applications et comportementales (taux d'échec, temps de réponse, etc).

Q4

La première chose que je testerais ici c'est la sécurité! Est-ce que la page est vulnérable aux injections SQL?

Un autre cas intéressant ici pourrait être des "smoke tests", où on bombarde l'application de création de compte. En autre, il serait intéressant de tester des "race conditions" où plusieurs personnes prennent le même nom d'utilisateur.

Ensuite, des tests de charge pourraient être intéressant si l'application sera déployée à un grand nombre d'utilisateurs.