unittest - python 2.7 mock
¿Cómo me burlo de un abierto usado en una declaración con(usando el framework Mock en Python)? (6)
¿Cómo pruebo el siguiente código con simulaciones (usando los simuladores, el decorador de parches y los centinelas provistos por el marco simulado de Michael Foord ):
def testme(filepath):
with open(filepath, ''r'') as f:
return f.read()
Con las últimas versiones de simulacro, puedes usar el ayudante mock_open realmente útil:
mock_open (simulacro = Ninguno, read_data = Ninguno)
Una función auxiliar para crear un simulacro para reemplazar el uso de abierto. Funciona para abrir llamado directamente o como administrador de contexto.
El argumento simulado es el objeto simulado para configurar. Si no tiene ninguno (el valor predeterminado), se creará un MagicMock para usted, con la API limitada a los métodos o atributos disponibles en los identificadores de archivo estándar.
read_data es una cadena para el método de lectura del manejador de archivo a devolver. Esta es una cadena vacía por defecto.
>>> 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'')
Hay mucho ruido en estas respuestas; casi todos son correctos pero desactualizados y no prolijos. mock_open
es parte del framework mock
y es muy simple de usar. patch
utilizado como contexto devuelve el objeto utilizado para reemplazar el parcheado: puede usarlo para simplificar su prueba.
Python 3.x
Use builtins
lugar 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
no es parte de la __builtin__
y debe parchar __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")
Caja de decorador
Si usa patch
como decorador usando el resultado de mock_open()
ya que el argumento del new
patch
puede ser un poco extraño.
En este caso, es mejor usar el new_callable
patch
new_callable
y recuerde que cada argumento adicional que el patch
no utiliza se pasará a la función new_callable
como se describe en patch .
patch () toma argumentos de palabra clave arbitrarios. Estos se pasarán a la Mock (o new_callable) en la construcción.
Por ejemplo, la versión decorada para Python 3.x es:
@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")
Recuerde que en este caso el patch
agregará el objeto simulado como argumento de su función de prueba.
La forma de hacer esto ha cambiado en el simulador 0.7.0 que finalmente admite la burla de los métodos de protocolo de python (métodos mágicos), particularmente usando el MagicMock:
http://www.voidspace.org.uk/python/mock/magicmock.html
Un ejemplo de burla abierta como administrador de contexto (de la página de ejemplos en la documentación de simulacro):
>>> 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'')
La respuesta principal es útil, pero la amplié un poco.
Si desea establecer el valor de su objeto de archivo (la f
en as f
) en función de los argumentos pasados a open()
aquí hay una manera de hacerlo:
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
Básicamente, open()
devolverá un objeto y llamará a __enter__()
en ese objeto.
Para simular correctamente, debemos simular open()
para devolver un objeto simulado. Ese objeto simulado se burlaría de la __enter__()
( MagicMock
lo hará por nosotros) para devolver el objeto simulado / archivo que queremos (de ahí mm.__enter__.return_value
). Hacer esto con 2 simulacros del modo anterior nos permite capturar los argumentos pasados a open()
y pasarlos a nuestro método do_something_with_data
.
Pasé un archivo de simulación completo como una cadena para open()
y mi do_something_with_data
veía así:
def do_something_with_data(*args, **kwargs):
return args[0].split("/n")
Esto transforma la cadena en una lista para que pueda hacer lo siguiente como lo haría con un archivo normal:
for line in file:
#do action
Para usar mock_open para un archivo simple, read()
(el fragmento de mock_open original que ya se proporciona en esta página está más orientado a la escritura):
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()
Tenga en cuenta que para documentos para mock_open, esto es específicamente para read()
, por lo que no funcionará con patrones comunes como for line in f
, por ejemplo.
Utiliza python 2.6.6 / simulacro 1.0.1
Puede ser que llegue un poco tarde al juego, pero esto funcionó para mí cuando llamé para open
en otro módulo sin tener que crear un nuevo archivo.
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")
Al parchear la función open
dentro del módulo __builtin__
a mi mock_open()
, puedo mock_open()
que escribo en un archivo sin crear uno.
Nota: Si está utilizando un módulo que usa cython, o su programa depende de cython de alguna manera, tendrá que importar el módulo __builtin__ de __builtin__
incluyendo la import __builtin__
en la parte superior de su archivo. No podrá burlarse del __builtin__
universal si está usando cython.