Dans cette phrase
Explique. En Python3, MagicMock est inclus dans le module standard unittest.mock.
En Python2, vous pouvez l'utiliser en installant le paquetage fictif avec pip install mock
.
Lancez l'interpréteur Python et créez un objet MagicMock
$ python3.6
Python 3.6.0 (default, Feb 27 2017, 00:03:01)
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.42.1)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from unittest.mock import MagicMock
>>> f = MagicMock()
Je suppose que ce f
est une fonction et j'essaye de l'appeler
>>> f(1)
<MagicMock name='mock()' id='4381867704'>
Je peux l'appeler même si je ne l'ai pas défini comme une fonction. C'est étrange. La valeur de retour est également MagicMock, mais je m'en fiche et je l'appellerai plus loin
>>> f(2)
<MagicMock name='mock()' id='4381867704'>
>>> f(1, 2, 3)
<MagicMock name='mock()' id='4381867704'>
Je pourrais l'appeler librement même si je changeais la valeur de l'argument et le nombre d'arguments. Je suis surpris. Si vous essayez d'évaluer f.call_args_list
ici,
>>> f.call_args_list
[call(1), call(2), call(1, 2, 3)]
Je l'ai appelé trois fois depuis que j'ai créé MagicMock. Vous pouvez voir qu'il est enregistré avec les arguments. c'est intéressant.
Ce n'est pas la seule fonctionnalité de MagicMock. Créons à nouveau une instance MagicMock, définissons la valeur sur f.return_value
, puis appelons f
.
>>> f = MagicMock()
>>> f.return_value = 5
>>> f(1, 2)
5
>>> f(1)
5
>>> f()
5
Quel que soit l'argument que vous donnez, la valeur définie sera renvoyée. De cette façon, vous pouvez remplacer la valeur de retour de la fonction par la valeur de votre choix. Dans ce cas également, la manière dont l'appel a été effectué est enregistrée.
>>> f.call_args_list
[call(1, 2), call(1), call()]
Il existe d'autres fonctionnalités, mais laissons cela de côté pour l'instant et voyons comment elles peuvent vous aider.
Supposons que vous ayez une fonction push_if_even ()
qui prend un entier, appelle push ()
si elle est paire, et ne fait rien si elle est impaire.
Plus précisément, le code est le suivant.
def push():
pass
def push_if_even(x):
"""Reçoit un entier et pousse s'il est pair()Appel"""
if x % 2 == 0:
push()
Supposons maintenant que vous souhaitiez écrire un test pour voir si ce code est correctement implémenté. Comme nous l'avons vu précédemment, MagicMock garde un enregistrement de ce qui a été appelé en tant que fonction, nous en profitons donc. Vous pouvez le tester en procédant comme suit:
from unittest.mock import MagicMock
push = MagicMock()
push_if_even(1)
assert len(push.call_args_list) == 0
push = MagicMock()
push_if_even(0)
assert len(push.call_args_list) == 1
print("success")
Vous pouvez également écrire comme suit
push = MagicMock()
push_if_even(1)
push.asset_not_called()
push = MagicMock()
push_if_even(0)
push.assert_called_once()
Jetons un coup d'œil à ce qui se passe lorsque l'assertion échoue.
>>> from unittest.mock import MagicMock
>>> push = MagicMock()
>>> push.assert_called_once()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/Cellar/python3/3.6.0/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/mock.py", line 795, in assert_called_once
raise AssertionError(msg)
AssertionError: Expected 'mock' to have been called once. Called 0 times.
>>> push()
<MagicMock name='mock()' id='4356157392'>
>>> push.assert_not_called()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/Cellar/python3/3.6.0/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/mock.py", line 777, in assert_not_called
raise AssertionError(msg)
AssertionError: Expected 'mock' to not have been called. Called 1 times.
Une fonction qui renvoie True si aujourd'hui est dimanche, False sinon ʻis_sunday`
from datetime import date
def today():
return date.today()
def is_sunday():
return today().weekday() == 6
Supposons que vous souhaitiez tester qui fonctionne correctement. Si aujourd'hui n'est pas dimanche, vous pouvez l'appeler une fois et voir qu'il renvoie False, puis attendre le dimanche suivant et le rappeler pour voir qu'il renvoie True. Cependant, il faudra des jours pour terminer le test. Si vous ne pouvez pas attendre cela, utilisez la capacité de MagicMock à contrôler la valeur de retour.
from unittest.mock import MagicMock
today = MagicMock()
today.return_value = date(2020, 2, 1)
assert is_sunday() == False
today = MagicMock()
today.return_value = date(2020, 2, 2)
assert is_sunday() == True
print("success")
Si tel est le cas, vous pouvez le tester en un instant. C'est pratique.
Après avoir vu la nature de MagicMock,
J'ai implémenté le code de test en utilisant la fonction de. Le test des fonctions qui affectent ou sont affectées par l'environnement est plus difficile à écrire que le test de fonctions simples, mais vous pouvez vous moquer de l'impact sur l'environnement ou stuber l'impact de l'environnement. Nous avons vu qu'il est facile de créer un code de test reproductible en le remplaçant.
Dans cet exemple, j'ai simplement écrasé la fonction, mais le module fictif a un élément pratique appelé patch, qui permet de remplacer facilement la fonction uniquement pendant le test, puis de la restaurer. Utilisez-le lors de la rédaction de tests.
Recommended Posts