Plus facile à lire avec un fond crème, une teinte, plus de contraste ou un texte plus grand ? Choisissez vos couleurs et votre texte, une fois pour toutes les pages.

Leçon gratuite

Remplacer une dépendance par un faux

Après cette leçon: Je peux tester un code qui dépend d’une horloge ou d’un tirage au hasard en les remplaçant par un faux.

Leçon de 55 min7 commandesLab Linux du quotidien : la trentaine de commandes que les ingénieurs tapent de tête

Qu’est-ce qu’une doublure de test ?

Une doublure de test, appelée aussi faux ou mock, est un composant simple qui remplace une dépendance pendant un test. Cette dépendance est une horloge, un tirage au hasard ou un service lent. Elle rend le résultat prévisible, donc le test donne toujours la même réponse.

Une application de métro affiche le prix du billet selon l’heure. Un test qui lit l’heure réelle réussit à midi et échoue à huit heures.

À la fin de cette leçon

Remarque

Je peux tester un code qui dépend d’une horloge ou d’un tirage au hasard en les remplaçant par un faux.

Mots-clés

MotCe que ça veut direExemple
Dépendancece dont une fonction a besoin et qu’elle ne contrôle pasl’heure, le hasard, un réseau
Doublure de testun faux composant qui remplace la vraie dépendance pendant un test
Bouchonune doublure qui rend toujours la même réponseune horloge qui dit toujours 8
Espionune doublure qui retient comment on l’a appelée
Simulacreune doublure qui se vérifie elle-même, appelée mock en anglais
Test instableun test qui réussit parfois et échoue parfois sans que le code change

Les cellules que les étudiants remplissent restent vides dans cet aperçu.

Un test qui dépend de l’heure est instable

Voici la règle du métro : de 7 h à 9 h et de 17 h à 19 h, le billet coûte 250 centimes. Le reste du temps, il coûte 190.

Si la fonction lit elle-même l’heure de la machine, son résultat change au fil de la journée. Un test qui réussit à midi et échoue à huit heures est un test instable. Il apprend à tout le monde à ne plus croire les tests.

Lire l’heure de la machine

Commande
date +%H

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Passer l’horloge en paramètre

La commande affiche l’heure sur deux chiffres. Elle sera autre dans une heure, et c’est bien le problème.

La solution est de ne pas lire l’heure dans la fonction. On lui passe une horloge, c’est-à-dire une fonction qui rend l’heure. En production, on donne la vraie. Dans un test, on donne un faux.

Une fonction qui reçoit son horloge

Code: python
def tarif_metro(horloge):
    heure = horloge()
    if 7 <= heure < 9 or 17 <= heure < 19:
        return 250
    return 190

# Un bouchon : une horloge qui dit toujours 8.
def horloge_8h():
    return 8

# Un autre bouchon : toujours midi.
def horloge_midi():
    return 12

assert tarif_metro(horloge_8h) == 250
assert tarif_metro(horloge_midi) == 190
print("Les deux tarifs sont justes, à toute heure")

Écrire la fonction du métro

Commande
printf 'def tarif_metro(horloge):\n    heure = horloge()\n    if 7 <= heure < 9 or 17 <= heure < 19:\n        return 250\n    return 190\n' > essais/metro.py

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Écrire deux tests avec des bouchons

Commande
printf 'import unittest\nfrom metro import tarif_metro\n\n\ndef horloge_8h():\n    return 8\n\n\ndef horloge_midi():\n    return 12\n\n\nclass TestsMetro(unittest.TestCase):\n    def test_heure_de_pointe(self):\n        self.assertEqual(tarif_metro(horloge_8h), 250)\n\n    def test_heure_creuse(self):\n        self.assertEqual(tarif_metro(horloge_midi), 190)\n' > essais/test_metro.py

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Lancer les tests : OK à toute heure

Commande
python3 -m unittest discover -s essais -p "test_metro.py" 2>&1 | tail -1

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Bouchon, espion, simulacre : trois sortes de faux

Un bouchon rend une réponse fixe : l’horloge qui dit 8. Un espion retient comment on l’a appelée : combien de fois, avec quoi. Un simulacre (mock) fait les deux et vérifie lui-même ses appels.

Python en fournit un dans unittest.mock. Les deux commandes qui suivent montrent un faux qui rend toujours 8, puis le nombre de fois qu’on l’a appelé.

Un faux qui rend toujours 8

Commande
python3 -c "from unittest.mock import Mock; m = Mock(return_value=8); print(m())"

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Compter les appels d’un faux

Commande
python3 -c "from unittest.mock import Mock; m = Mock(return_value=8); m(); m(); print(m.call_count)"

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Le hasard se remplace comme l’horloge

Un tirage au sort pose le même problème : le résultat change à chaque essai. On passe donc en paramètre la fonction qui tire.

Un faux tirage rend toujours la même place, par exemple la première. Le test sait alors qui doit gagner.

Un tirage au sort remplaçable

Code: python
def choisir_gagnant(participants, tirage):
    place = tirage(len(participants))
    return participants[place]

# Un espion : il retient la taille qu'on lui a donnée et rend toujours la place 1.
appels = []

def tirage_espion(taille):
    appels.append(taille)
    return 1

gagnant = choisir_gagnant(["Aya", "Bao", "Chen"], tirage_espion)
print(gagnant, appels)

Le vrai hasard reste imprévisible

Commande
python3 -c "import random; print(random.randint(1, 6) in [1, 2, 3, 4, 5, 6])"

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Erreur fréquente

Attention

Ne remplacez jamais ce que vous testez : ce serait tester le faux. Remplacez seulement ce qui échappe à votre contrôle, comme l’heure ou le réseau. Gardez aussi un test avec la vraie dépendance, plus haut dans la pyramide.

Écrire du code testable avec un faux

Dans le devoir, vous écrivez deux fonctions qui reçoivent leur dépendance. message_accueil(horloge) dit Bonjour, Bon après-midi ou Bonsoir selon l’heure. tirer_gagnant(participants, tirage) rend le participant que le tirage désigne.

Les tests cachés leur donnent des horloges et des tirages truqués. Votre code ne doit jamais lire la vraie heure.

À propos de ce labo et de sa source: Lab Linux du quotidien : la trentaine de commandes que les ingénieurs tapent de tête

Vous enseignez à une classe ? Proposez ce module à vos étudiants avec un guide de l'enseignant, des devoirs corrigés et un laboratoire pour chaque étudiant.