python - Mocking abierto(file_name) en pruebas unitarias
unit-testing mox (7)
Me tomé la libertad de volver a escribir tu función de muestra:
Suponga que su función se encuentra en un archivo llamado code.py
# code.py
import csv
import logging
def ParseCsvFile(source):
"""Parse the csv file.
Args:
source: file to be parsed
Returns: the list of dictionary entities; each dictionary contains
attribute to value mapping or its equivalent.
"""
global rack_file
rack_file = source
attributes_list = []
try:
rack_type_file = open(rack_file)
except IOError, (errno, strerror):
logging.error("I/O error(%s): %s", errno, strerror)
else:
reader = csv.DictReader(rack_type_file, delimiter='','')
attributes_list = [line for line in reader] # list of dictionaries
rack_type_file.close()
return attributes_list
Un caso de prueba simple sería:
# your test file
import __builtin__
import unittest
import contextlib
from StringIO import StringIO
import mox
import code
@contextlib.contextmanager
def mox_replayer(mox_instance):
mox_instance.ReplayAll()
yield
mox_instance.VerifyAll()
class TestParseCSVFile(unittest.TestCase):
def setUp(self):
self.mox = mox.Mox()
def tearDown(self):
self.mox.UnsetStubs()
def test_parse_csv_file_returns_list_of_dicts(self):
TEST_FILE_NAME = ''foo.csv''
self.mox.StubOutWithMock(__builtin__, ''open'')
open(TEST_FILE_NAME).AndReturn(StringIO("name,age/nfoo,13"))
with mox_replayer(self.mox):
result = code.ParseCsvFile(TEST_FILE_NAME)
self.assertEqual(result, [{''age'': ''13'', ''name'': ''foo''}]) # works!
if __name__ == ''__main__'':
unittest.main()
EDITAR:
% /usr/bin/python2.6
Python 2.6.1 (r261:67515, Jun 24 2010, 21:47:49)
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import __builtin__
>>> import mox
>>> mock = mox.Mox()
>>> mock.StubOutWithMock(__builtin__, ''open'')
>>> mock.UnsetStubs()
Funciona bien en 2.6 usando mox 0.53
Tengo un código fuente que abre un archivo csv y configura un encabezado para valorar la asociación. El código fuente se da a continuación:
def ParseCsvFile(source):
"""Parse the csv file.
Args:
source: file to be parsed
Returns: the list of dictionary entities; each dictionary contains
attribute to value mapping or its equivalent.
"""
global rack_file
rack_type_file = None
try:
rack_file = source
rack_type_file = open(rack_file) # Need to mock this line.
headers = rack_type_file.readline().split('','')
length = len(headers)
reader = csv.reader(rack_type_file, delimiter='','')
attributes_list=[] # list of dictionaries.
for line in reader:
# More process to happeng. Converting the rack name to sequence.
attributes_list.append(dict((headers[i],
line[i]) for i in range(length)))
return attributes_list
except IOError, (errno, strerror):
logging.error("I/O error(%s): %s" % (errno, strerror))
except IndexError, (errno, strerror):
logging.error(''Index Error(%s), %s'' %(errno, strerror))
finally:
rack_type_file.close()
Estoy tratando de burlarme de la siguiente declaración rack_type_file = open (rack_file) ¿Cómo me burlo de la función open (...)? Cualquier ayuda sería apreciada
>>> class A(object):
... def __init__(self):
... self.x = open(''test.py'')
...
>>> old_open = open
>>> def open(s):
... return "test/n"
...
>>> a = A()
>>> a.x
''test/n''
>>> open = old_open
>>> a = A()
>>> a.x
<open file ''test.py'', mode ''r'' at 0xb7736230>
Para __builtin__
función incorporada abierta con mox use el módulo __builtin__
:
import __builtin__ # unlike __builtins__ this must be imported
m = mox.Mox()
m.StubOutWithMock(__builtin__, ''open'')
open(''ftphelp.yml'', ''rb'').AndReturn(StringIO("fake file content"))
m.ReplayAll()
# call the code you want to test that calls `open`
m.VerifyAll()
m.UnsetStubs()
Tenga en cuenta que __builtins__
no es siempre un módulo, puede ser de tipo dict, por favor utilice el __builtin__
(sin "s") para referirse a los métodos integrados del sistema.
Más sobre el módulo __builtin__
: http://docs.python.org/library/ builtin .html
Hay dos formas en que me gusta hacer esto, dependiendo de la situación.
Si su prueba unitaria va a llamar a ParseCsvFile directamente, agregaría un nuevo kwarg a ParseCsvFile:
def ParseCsvFile(source, open=open):
# ...
rack_type_file = open(rack_file) # Need to mock this line.
Entonces su prueba unitaria puede pasar un open_func diferente para lograr la burla.
Si la prueba de su unidad llama a alguna otra función que a su vez llame a ParseCsvFile, pasar alrededor de open_func solo para las pruebas es feo. En ese caso, usaría el módulo simulado . Esto le permite modificar una función por nombre y reemplazarla por un objeto Mock.
# code.py
def open_func(name):
return open(name)
def ParseCsvFile(source):
# ...
rack_type_file = open_func(rack_file) # Need to mock this line.
# test.py
import unittest
import mock
from StringIO import StringIO
@mock.patch(''code.open_func'')
class ParseCsvTest(unittest.TestCase):
def test_parse(self, open_mock):
open_mock.return_value = StringIO("my,example,input")
# ...
Hola, estaba teniendo un problema similar, y me estaba arrancando el pelo moviéndome entre diferentes bibliotecas de burlas. Finalmente encontré una solución con la que estoy contento, ¿y quizás te pueda ayudar? Al final fui con la biblioteca de Mocker http://labix.org/mocker y aquí está el código para la burla abierta:
from mocker import Mocker
from StringIO import StringIO
import __builtin__
mocker = Mocker()
sourceFile = ''myTestFile.txt''
__builtin__.open = mocker.mock()
__builtin__.open(sourceFile)
mocker.result(StringIO(''this,is,a,test,file''))
<the rest of your test setup goes here>
mocker.replay()
ParseCsvFile(sourceFile)
mocker.restore()
mocker.verify()
Incidentalmente, la razón por la que fui con Mocker es porque estaba probando una función que usaba abierta para leer un archivo, y luego la usé para sobrescribir el mismo archivo con nuevos datos. Lo que tenía que hacer era probar el caso en el que el archivo inicial no existía, así que configuró un simulacro, que lanzó un IOError la primera vez, y luego funcionó la segunda vez. La configuración para la cual se veía así:
from mocker import Mocker
import __builtin__
mocker = Mocker()
mockFileObject = mocker.mock()
__builtin__.open = mocker.mock()
__builtin__.open(''previousState.pkl'', ''r'')
mocker.throw(IOError(''Boom''))
__builtin__.open(''previousState.pkl'',''w'')
mocker.result(mockFileObject)
<rest of test setup >
mocker.replay()
<test>
mocker.restore() #required to restore the open method
mocker.verify()
¡Espero que esto ayude!
Esta es ciertamente una vieja pregunta, por lo tanto, algunas de las respuestas están desactualizadas.
En la versión actual de la biblioteca mock
hay una función de conveniencia diseñada precisamente para este propósito . Así es como funciona:
>>> from mock import mock_open
>>> m = mock_open()
>>> with patch(''__main__.open'', m, create=True):
... with open(''foo'', ''w'') as h:
... h.write(''some stuff'')
...
>>> m.mock_calls
[call(''foo'', ''w''),
call().__enter__(),
call().write(''some stuff''),
call().__exit__(None, None, None)]
>>> m.assert_called_once_with(''foo'', ''w'')
>>> handle = m()
>>> handle.write.assert_called_once_with(''some stuff'')
La documentación está aquí .
Es simple con el decorador (Python3):
def my_method():
with open(file="/1.txt", mode=''r'', encoding=''utf-8'') as file:
return file.read().strip()
@mock.patch("builtins.open", create=True)
def test_my_method(mock_open):
mock_open.side_effect = [
mock.mock_open(read_data="A").return_value
]
resA = my_method()
assert resA == "A"
mock_open.mock_calls == [mock.call(file="/1.txt", mode=''r'', encoding=''utf-8'')]