我想写一个测试,帮助我确定我使用的库的API是否已经改变,例如:升级后。
如果我要创建一个"盲目模拟"对象然后模拟将始终使用一个方法,测试将通过,但我的应用程序将打破实际的库。
我知道有一种修补现有对象的方法:
@patch.object(ZipFile, 'namelist')
def test_my_method(self, mocked_zipfile):
至少会检查namelist
方法是否实际存在于原始对象上,但它仍然允许我在模拟内部对象时输入错误:
@patch.object(ZipFile, 'namelist')
def test_my_method(self, mocked_zipfile):
mocked_zipfile.namlist.return_value = [ 'one.txt', 'two.txt' ]
当我在测试中和测试代码中输入拼写错误(namlist
)时,测试将默默地通过。
有没有什么方法可以阻止猴子修补不存在的模拟对象的方法,除非每次我编写测试时都记住它(当你有一个团队并且你想自动检查这些时,这不是最好的方法的东西)?
答案 0 :(得分:3)
您可以使用autospec=True
修补zipfile.Zipfile
:
如果设置
autospec=True
,则使用规范创建模拟 从被替换的对象。模拟的所有属性也将 具有对象的相应属性的规范 更换。被模拟的方法和函数将有其参数 如果被错误调用,则会检查并引发TypeError
签名。对于模拟替换类,它们的返回值( 'instance')将与该类具有相同的规范。
由于AttributeError: Mock object has no attribute 'namlist'
:
from unittest import TestCase
from mock import patch
class MyTestCase(TestCase):
@patch.object(ZipFile, 'namelist', autospec=True)
def test_my_method(self, mocked_zipfile):
mocked_zipfile.namlist.return_value = [ 'one.txt', 'two.txt' ]
希望有所帮助。
答案 1 :(得分:2)
您是否尝试过使用wraps
关键字参数?
这对我有用:
>>> from mock import Mock
>>> import zipfile
>>> mocked_zipfile = Mock(wraps=zipfile.ZipFile)
>>> mocked_zipfile.namlist.return_value = ['one.txt', 'two.txt']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/jbaiter/.envs/spreads/local/lib/python2.7/site-packages/mock.py", line 670, in __getattr__
wraps = getattr(self._mock_wraps, name)
AttributeError: type object 'ZipFile' has no attribute 'namlist'
>>> mocked_zipfile.namelist.return_value = ['one.txt', 'two.txt']
>>> mocked_zipfile.namelist()
['one.txt', 'two.txt']
我还没有尝试使用@patch
装饰方法,但这应该可行:
@patch('zipfile.ZipFile', Mock(wraps=zipfile.ZipFile))
def test_my_method(self, mocked_zipfile):
# call code that depends on ZipFile
pass