如何禁止猴子修补不存在的模拟方法?

时间:2014-04-25 11:32:21

标签: python unit-testing python-2.7 monkeypatching python-unittest

我想写一个测试,帮助我确定我使用的库的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)时,测试将默默地通过。

有没有什么方法可以阻止猴子修补不存在的模拟对象的方法,除非每次我编写测试时都记住它(当你有一个团队并且你想自动检查这些时,这不是最好的方法的东西)?

2 个答案:

答案 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