Puisque vous dites que vous êtes nouveau dans les tests unitaires et que vous avez demandé des objets fictifs en "termes simples", je vais essayer l'exemple d'un profane.
Test unitaire
Imaginez des tests unitaires pour ce système:
cook <- waiter <- customer
Il est généralement facile d'envisager de tester un composant de bas niveau comme cook
:
cook <- test driver
Le testeur commande simplement différents plats et vérifie que le cuisinier renvoie le plat correct pour chaque commande.
Il est plus difficile de tester un composant intermédiaire, comme le serveur, qui utilise le comportement d'autres composants. Un testeur naïf pourrait tester le composant serveur de la même manière que nous avons testé le composant cook:
cook <- waiter <- test driver
Le pilote d'essai commandait différents plats et s'assurait que le serveur renvoie le bon plat. Malheureusement, cela signifie que ce test du composant serveur peut dépendre du comportement correct du composant de cuisson. Cette dépendance est encore pire si le composant cuisinier a des caractéristiques peu conviviales pour les tests, comme un comportement non déterministe (le menu comprend la surprise du chef comme plat), beaucoup de dépendances (le cuisinier ne cuisinera pas sans tout son personnel), ou beaucoup de ressources (certains plats nécessitent des ingrédients coûteux ou prennent une heure à cuire).
Puisqu'il s'agit d'un test de serveur, idéalement, nous voulons tester uniquement le serveur, pas le cuisinier. Plus précisément, nous voulons nous assurer que le serveur transmet correctement la commande du client au cuisinier et livre correctement la nourriture du cuisinier au client.
Le test unitaire signifie tester les unités indépendamment, donc une meilleure approche serait d'isoler le composant testé (le serveur) en utilisant ce que Fowler appelle des doubles de test (mannequins, stubs, faux, simulacres) .
-----------------------
| |
v |
test cook <- waiter <- test driver
Ici, le cuisinier de test est "de mèche" avec le pilote de test. Idéalement, le système testé est conçu de manière à ce que le cuisinier test puisse être facilement remplacé ( injecté ) pour travailler avec le serveur sans changer le code de production (par exemple sans changer le code serveur).
Objets simulés
Maintenant, le test cook (test double) pourrait être implémenté de différentes manières:
- un faux cuisinier - quelqu'un se faisant passer pour un cuisinier en utilisant des plats surgelés et un micro-ondes,
- un chef cuisinier - un vendeur de hot-dogs qui vous donne toujours des hot-dogs, peu importe ce que vous commandez, ou
- un cuisinier simulé - un flic infiltré suivant un scénario se faisant passer pour un cuisinier dans une opération de piqûre.
Voir l'article de Fowler pour plus de détails sur les faux vs les talons vs les mocks vs les mannequins , mais pour l'instant, concentrons-nous sur un simulacre de cuisinier.
-----------------------
| |
v |
mock cook <- waiter <- test driver
Une grande partie des tests unitaires du composant serveur se concentre sur la manière dont le serveur interagit avec le composant cuisinier. Une approche basée sur des simulations se concentre sur la spécification complète de l'interaction correcte et sur la détection des dysfonctionnements.
L'objet fictif sait à l'avance ce qui est censé se passer pendant le test (par exemple, lequel de ses appels de méthodes sera invoqué, etc.) et l'objet fictif sait comment il est censé réagir (par exemple, quelle valeur de retour fournir). Le simulacre indiquera si ce qui se passe réellement diffère de ce qui est censé se produire. Un objet fictif personnalisé pourrait être créé à partir de zéro pour chaque cas de test afin d'exécuter le comportement attendu pour ce cas de test, mais un cadre de simulation s'efforce de permettre à une telle spécification de comportement d'être clairement et facilement indiquée directement dans le cas de test.
La conversation autour d'un test basé sur une simulation pourrait ressembler à ceci:
pilote d'essai pour simuler un cuisinier : attendez-vous à une commande de hot-dog et donnez-lui ce faux hot-dog en réponse
pilote d'essai (se faisant passer pour un client) au serveur : je voudrais un hot-dog s'il vous plaît le
serveur se moque du cuisinier : 1 hot-dog s'il vous plaît
simulez le cuisinier au serveur : commandez: 1 hot-dog prêt (donne un hot-dog factice au serveur)
serveur pour tester le pilote : voici votre hot-dog (donne un hot-dog factice au pilote d'essai)
pilote d'essai : TEST RÉUSSI!
Mais comme notre serveur est nouveau, voici ce qui pourrait arriver:
pilote d'essai pour simuler un cuisinier : attendez-vous à une commande de hot-dog et donnez-lui ce faux hot-dog en réponse
pilote d'essai (se faisant passer pour un client) au serveur : je voudrais un hot-dog s'il vous plaît
serveur pour simuler le cuisinier : 1 hamburger s'il vous plaît
mock cook arrête le test: on m'a dit d'attendre une commande de hot-dog!
le pilote de test note le problème: TEST ECHEC! - le serveur a changé la commande
ou
pilote d'essai pour simuler un cuisinier : attendez-vous à une commande de hot-dog et donnez-lui ce faux hot-dog en réponse
pilote d'essai (se faisant passer pour un client) au serveur : je voudrais un hot-dog s'il vous plaît le
serveur se moque du cuisinier : 1 hot-dog s'il vous plaît
simulez le cuisinier au serveur : commandez: 1 hot-dog prêt (donne un hot-dog factice au serveur)
serveur pour tester le pilote : voici vos frites (donne des frites d'un autre ordre pour tester le pilote)
pilote d'essai note les frites inattendues: TEST ECHEC! le serveur a rendu le mauvais plat
Il peut être difficile de voir clairement la différence entre les objets fictifs et les stubs sans un exemple contrastant basé sur les stub pour aller avec cela, mais cette réponse est déjà bien trop longue :-)
Notez également qu'il s'agit d'un exemple assez simpliste et que les frameworks moqueurs permettent des spécifications assez sophistiquées du comportement attendu des composants pour prendre en charge des tests complets. Il y a beaucoup de matériel sur les objets simulés et les frameworks moqueurs pour plus d'informations.