Comment puis-je outragent un ouvert utilisé dans une déclaration avec (en utilisant le cadre de simulation en Python)?

StackOverflow https://stackoverflow.com/questions/1289894

  •  18-09-2019
  •  | 
  •  

Question

Comment puis-je tester le code suivant avec simulacres (en utilisant des simulacres, le décorateur de patch et fournies par factionnaires Michael cadre de simulation de Foord de ):

def testme(filepath):
    with open(filepath, 'r') as f:
        return f.read()
Était-ce utile?

La solution

La façon de faire a changé en faux 0.7.0 qui soutient enfin se moquant des méthodes de protocole python (méthodes magiques), en particulier en utilisant la MagicMock:

http://www.voidspace.org.uk/python/mock/magicmock.html

Un exemple de moqueur ouvert en tant que gestionnaire de contexte (à partir de la page d'exemples dans la documentation maquette):

>>> open_name = '%s.open' % __name__
>>> with patch(open_name, create=True) as mock_open:
...     mock_open.return_value = MagicMock(spec=file)
...
...     with open('/some/path', 'w') as f:
...         f.write('something')
...
<mock.Mock object at 0x...>
>>> file_handle = mock_open.return_value.__enter__.return_value
>>> file_handle.write.assert_called_with('something')

Autres conseils

Il y a beaucoup de bruit dans ces réponses; presque tous sont corrects, mais pas à jour et non soignée. mock_open fait partie de mock cadre et est très simple à utiliser. patch utilisé comme contexte renvoie l'objet utilisé pour remplacer le patched :. vous pouvez l'utiliser pour faire votre test plus simple

3.x Python

Utiliser builtins au lieu de __builtin__.

from unittest.mock import patch, mock_open
with patch("builtins.open", mock_open(read_data="data")) as mock_file:
    assert open("path/to/open").read() == "data"
    mock_file.assert_called_with("path/to/open")

Python 2.7

mock ne fait pas partie de unittest et vous devez patcher __builtin__

from mock import patch, mock_open
with patch("__builtin__.open", mock_open(read_data="data")) as mock_file:
    assert open("path/to/open").read() == "data"
    mock_file.assert_called_with("path/to/open")

cas décorateur

Si vous utilisez patch comme décorateur en utilisant le résultat de mock_open() comme argument de new patch peut être un peu bizarre.

Dans ce cas est préférable d'utiliser l'argument de new_callable patch et rappelez-vous que seront transmis tous les arguments supplémentaires qui patch n'utilise pas new_callable fonction comme décrit dans documentation patch .

  patch ()

prend des arguments de mots clés arbitraires. Ces derniers seront transmis à la Mock (ou new_callable) sur la construction.

Par exemple la version décorée pour 3.x Python est:

@patch("builtins.open", new_callable=mock_open, read_data="data")
def test_patch(mock_file):
    assert open("path/to/open").read() == "data"
    mock_file.assert_called_with("path/to/open")

Rappelez-vous que dans ce cas patch ajoutera l'objet fantaisie comme argument de vous fonction de test.

Avec les dernières versions de la maquette, vous pouvez utiliser le mock_open vraiment utile aide:

  

mock_open (mock = None, read_data = None)

     

Une fonction d'aide pour créer un   maquette pour remplacer l'utilisation de logiciels libres. Il travaille pour ouvert appelé directement ou   utilisé comme gestionnaire de contexte.

     

L'argument fictif est l'objet simulé pour configurer. Si aucune (la   par défaut), puis un MagicMock sera créé pour vous, avec l'API   limité à des méthodes ou des attributs disponibles sur les descripteurs de fichiers standard.

     

read_data est une chaîne pour la méthode de lecture de la poignée de fichier   revenir. Ceci est une chaîne vide par défaut.

>>> from mock import mock_open, patch
>>> m = mock_open()
>>> with patch('{}.open'.format(__name__), m, create=True):
...    with open('foo', 'w') as h:
...        h.write('some stuff')

>>> m.assert_called_once_with('foo', 'w')
>>> handle = m()
>>> handle.write.assert_called_once_with('some stuff')

Pour utiliser mock_open pour un simple fichier read() (l'extrait mock_open déjà donné sur cette page originale est davantage pour l'écriture):

my_text = "some text to return when read() is called on the file object"
mocked_open_function = mock.mock_open(read_data=my_text)

with mock.patch("__builtin__.open", mocked_open_function):
    with open("any_string") as f:
        print f.read()

Note comme par docs pour mock_open, cela est spécifiquement pour read(), donc ne fonctionnera pas avec des modèles communs comme for line in f, par exemple.

Utilise python 2.6.6 / 1.0.1 maquette

Je pourrais être un peu tard pour le jeu, mais cela a fonctionné pour moi lorsque vous appelez open dans un autre module sans avoir à créer un nouveau fichier.

test.py

import unittest
from mock import Mock, patch, mock_open
from MyObj import MyObj

class TestObj(unittest.TestCase):
    open_ = mock_open()
    with patch.object(__builtin__, "open", open_):
        ref = MyObj()
        ref.save("myfile.txt")
    assert open_.call_args_list == [call("myfile.txt", "wb")]

MyObj.py

class MyObj(object):
    def save(self, filename):
        with open(filename, "wb") as f:
            f.write("sample text")

En corrigeant la fonction open à l'intérieur du module __builtin__ à mon mock_open(), je peux écrire à se moquer d'un fichier sans en créer un.

Remarque: Si vous utilisez un module qui utilise cython, ou votre programme dépend de cython de toute façon, vous devez importer module __builtin__ de cython en incluant import __builtin__ en haut de votre fichier. Vous ne serez pas en mesure de se moquer de l'__builtin__ universel si vous utilisez cython.

La partie supérieure réponse est utile, mais j'étendu sur un peu.

Si vous souhaitez définir la valeur de votre objet de fichier (le f dans as f) sur la base des arguments passés à open() ici est une façon de le faire:

def save_arg_return_data(*args, **kwargs):
    mm = MagicMock(spec=file)
    mm.__enter__.return_value = do_something_with_data(*args, **kwargs)
    return mm
m = MagicMock()
m.side_effect = save_arg_return_array_of_data

# if your open() call is in the file mymodule.animals 
# use mymodule.animals as name_of_called_file
open_name = '%s.open' % name_of_called_file

with patch(open_name, m, create=True):
    #do testing here

En gros, open() retourne un objet et with appellera __enter__() sur cet objet.

Pour se moquer correctement, il faut se moquer de open() pour retourner un objet fantaisie. Cet objet maquette doit alors se moquer de l'appel __enter__() sur elle (MagicMock le fera pour nous) pour retourner les données simulées / objet fichier que nous voulons (et donc de mm.__enter__.return_value). Faire cela avec 2 se moque de la façon ci-dessus permet de saisir les arguments passés à open() et de les transmettre à notre méthode do_something_with_data.

J'ai passé un fichier maquette entier comme une chaîne à open() et mon do_something_with_data ressemblait à ceci:

def do_something_with_data(*args, **kwargs):
    return args[0].split("\n")

Ceci transforme la chaîne en une liste, vous pouvez donc faire ce qui suit comme vous le feriez avec un fichier normal:

for line in file:
    #do action
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top