Kar*_*tik 24 python unit-testing mox
我有一个源代码打开一个csv文件并设置一个标头值关联.源代码如下:
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()
Run Code Online (Sandbox Code Playgroud)
我试图嘲笑以下声明
rack_type_file = open(rack_file)
Run Code Online (Sandbox Code Playgroud)
我如何模拟open(...)函数?
mac*_*mac 22
这无疑是一个古老的问题,因此有些答案已经过时了.
在当前版本的mock库中,有一个便利功能,正是为此目的而设计的.以下是它的工作原理:
>>> 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')
Run Code Online (Sandbox Code Playgroud)
文档在这里.
Luk*_*tas 13
要使用mox使用__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()
Run Code Online (Sandbox Code Playgroud)
注意,__builtins__并不总是一个模块,它可以是dict类型,请使用__builtin__(没有"s")模块来引用系统内置方法.
有关__builtin__模块的更多信息:http://docs.python.org/library/ builtin .html
Spi*_*nim 10
根据具体情况,我喜欢这两种方式.
如果您的单元测试将直接调用ParseCsvFile,我会向ParseCsvFile添加一个新的kwarg:
def ParseCsvFile(source, open=open):
# ...
rack_type_file = open(rack_file) # Need to mock this line.
Run Code Online (Sandbox Code Playgroud)
然后您的单元测试可以传递不同的open_func以完成模拟.
如果你的单元测试调用一些其他函数,而这些函数又调用ParseCsvFile,那么为了测试而传递open_func是很难看的.在那种情况下,我会使用模拟模块.这允许您按名称更改函数并将其替换为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")
# ...
Run Code Online (Sandbox Code Playgroud)
使用装饰器(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')]
Run Code Online (Sandbox Code Playgroud)