Comment tester le code suivant avec des simulacres (en utilisant des simulations, le décorateur de patchs et les sentinelles fournis par le framework Mock de Michael Foord ):
def testme(filepath):
with open(filepath, 'r') as f:
return f.read()
python
mocking
with-statement
Daryl Spitzer
la source
la source
Réponses:
La façon de faire a changé dans mock 0.7.0 qui prend enfin en charge la moquerie des méthodes de protocole python (méthodes magiques), en particulier en utilisant MagicMock:
http://www.voidspace.org.uk/python/mock/magicmock.html
Un exemple de mocking ouvert en tant que gestionnaire de contexte (à partir de la page d'exemples dans la documentation fictive):
la source
__enter__
et simule également__exit__
des objets - cette dernière approche est-elle obsolète ou toujours utile?file
est parti!mock_open
fait partie dumock
framework et est très simple à utiliser.patch
utilisé comme contexte renvoie l'objet utilisé pour remplacer celui qui a été corrigé: vous pouvez l'utiliser pour simplifier votre test.Python 3.x
Utilisez à la
builtins
place de__builtin__
.Python 2.7
mock
ne fait pas partie deunittest
et vous devriez patcher__builtin__
Coffret décorateur
Si vous
patch
utilisiez comme décorateur en utilisantmock_open()
le résultat de s commenew
patch
argument de s, cela peut être un peu bizarre.Dans ce cas, il est préférable d 'utiliser l
new_callable
patch
' argument s et de se rappeler que tous les arguments supplémentaires quipatch
ne sont pas utilisés seront passés à lanew_callable
fonction comme décrit dans lapatch
documentation .Par exemple, la version décorée pour Python 3.x est:
N'oubliez pas que dans ce cas
patch
, vous ajouterez l'objet fictif comme argument de votre fonction de test.la source
with patch("builtins.open", mock_open(read_data="data")) as mock_file:
être converti en syntaxe de décorateur? J'ai essayé, mais je ne sais pas dans quoi je dois passer@patch("builtins.open", ...)
comme deuxième argument.return_value
ofmock_open
dans un autre objet fictif et affirmer le second mock'sreturn_value
), mais cela fonctionnait en ajoutantmock_open
asnew_callable
.six
module pour avoir unmock
module cohérent . Mais je ne sais pas si cela correspond égalementbuiltins
à un module commun.Avec les dernières versions de mock, vous pouvez utiliser l' assistant mock_open vraiment utile :
la source
.write
appels?handle.write.assert_any_call()
. Vous pouvez également utiliserhandle.write.call_args_list
pour recevoir chaque appel si la commande est importante.m.return_value.write.assert_called_once_with('some stuff')
est mieux imo. Évite d'enregistrer un appel.Mock.call_args_list
est plus sûr de déclarer manuellement about que d'appeler l'une desMock.assert_xxx
méthodes,. Si vous mal orthographiez l'un de ces derniers, étant des attributs de Mock, ils passeront toujours silencieusement.Pour utiliser mock_open pour un fichier simple
read()
(l'extrait de code original mock_open déjà donné sur cette page est davantage destiné à l'écriture):Notez que selon la documentation pour mock_open, ceci est spécifiquement pour
read()
, donc ne fonctionnera pas avec des modèles courants commefor line in f
, par exemple.Utilise python 2.6.6 / mock 1.0.1
la source
for line in opened_file:
type de code. J'ai essayé d'expérimenter avec StringIO itérable qui implémente__iter__
et de l'utiliser à la place demy_text
, mais pas de chance.read()
donc ne fonctionnera pas dans votrefor line in opened_file
cas; J'ai édité le message pour clarifierfor line in f:
charge de @EvgeniiPuchkaryov peut être obtenue en se moquant de la valeur de retour de enopen()
tant qu'objet StringIO .with open("any_string") as f: print f.read()
La première réponse est utile, mais je l'ai un peu développée.
Si vous souhaitez définir la valeur de votre objet fichier (le
f
inas f
) en fonction des arguments passés,open()
voici une façon de le faire:Fondamentalement,
open()
retournera un objet etwith
appellera__enter__()
cet objet.Pour se moquer correctement, il faut se moquer
open()
pour renvoyer un objet factice. Cet objet factice devrait alors se moquer de l'__enter__()
appel (leMagicMock
fera pour nous) pour renvoyer l'objet de données / fichier factice que nous voulons (par conséquentmm.__enter__.return_value
). Faire cela avec 2 mocks comme ci-dessus nous permet de capturer les arguments passés àopen()
et de les transmettre à notredo_something_with_data
méthode.J'ai passé un fichier simulé entier sous forme de chaîne à
open()
et mondo_something_with_data
ressemblait à ceci:Cela transforme la chaîne en une liste afin que vous puissiez faire ce qui suit comme vous le feriez avec un fichier normal:
la source
__enter__
? Cela ressemble définitivement plus à un hack qu'à une méthode recommandée.Je suis peut-être un peu en retard dans le jeu, mais cela a fonctionné pour moi lors de l'appel
open
d'un autre module sans avoir à créer un nouveau fichier.test.py
MyObj.py
En patchant la
open
fonction à l'intérieur du__builtin__
module sur mymock_open()
, je peux me moquer de l'écriture dans un fichier sans en créer un.Remarque: Si vous utilisez un module qui utilise cython, ou que votre programme dépend de cython de quelque manière que ce soit, vous devrez importer le
__builtin__
module de cython en l'incluantimport __builtin__
en haut de votre fichier. Vous ne pourrez pas vous moquer de l'universel__builtin__
si vous utilisez cython.la source
import __builtin__
à mon module de test. Cet article a aidé à clarifier pourquoi cette technique fonctionne aussi bien: ichimonji10.name/blog/6Pour patcher la fonction open () intégrée avec unittest:
Cela a fonctionné pour un correctif pour lire une configuration json.
L'objet simulé est l'objet io.TextIOWrapper renvoyé par la fonction open ()
la source
Si vous n'avez plus besoin de fichier, vous pouvez décorer la méthode de test:
la source