将mock.patch的autospec选项与自定义Mock子类一起使用

问题描述 投票:0回答:1

我正在尝试使用(反向移植)

mock
模块将间谍附加到类中的方法。也就是说,我想创建一个模拟,其工作方式与原始方法类似,但提供常用的
Mock
功能,如
call_count
等。

这是我当前使用的代码:

import mock

class MyClass(object):
    def my_method(self, arg):
        return arg + 1

def unit_under_test():
    inst = MyClass()
    return inst.my_method(1)

with mock.patch.object(MyClass, 'my_method', autospec=True,
                       side_effect=MyClass.my_method) as spy:
    result = unit_under_test()
    assert result == 2
    assert spy.call_count == 1

效果很好。现在我想改用

MagicMock
的自定义子类。
patch
文档
说这可以通过
new_callable
参数来完成。但是,
new_callable
autospec
不能一起使用:

class MyMock(mock.MagicMock):
    pass

with mock.patch.object(MyClass, 'my_method', autospec=True,
                       side_effect=MyClass.my_method,
                       new_callable=MyMock) as spy:
    ...
Traceback (most recent call last):
  File "./mocktest.py", line 19, in <module>
    new_callable=MyMock) as spy:
  File "/var/foo/venv/local/lib/python2.7/site-packages/mock.py", line 1442, in _patch_object
    spec_set, autospec, new_callable, kwargs
  File "/var/foo/venv/local/lib/python2.7/site-packages/mock.py", line 1127, in __init__
    "Cannot use 'autospec' and 'new_callable' together"
ValueError: Cannot use 'autospec' and 'new_callable' together

问题是省略

autospec
也不起作用,因为这样
self
就不会传递给原始方法:

with mock.patch.object(MyClass, 'my_method',
                       side_effect=MyClass.my_method,
                       new_callable=MyMock) as spy:
    ...
Traceback (most recent call last):
  File "./mocktest.py", line 20, in <module>
    result = unit_under_test()
  File "./mocktest.py", line 11, in unit_under_test
    return inst.my_method(1)
  File "/var/foo/venv/local/lib/python2.7/site-packages/mock.py", line 955, in __call__
    return _mock_self._mock_call(*args, **kwargs)
  File "/var/foo/venv/local/lib/python2.7/site-packages/mock.py", line 1018, in _mock_call
    ret_val = effect(*args, **kwargs)
TypeError: unbound method my_method() must be called with MyClass instance as first argument (got int instance instead)

请注意,我无法修补

my_method
instance
MyClass,因为我正在测试的代码创建了自己的
MyClass
实例(如上面的示例代码所示)。

python python-2.7 python-mock
1个回答
0
投票

由于设置

mock.py
MagicMock
hardcodes
autospec
作为模拟类,因此您必须使用
MagicMock
的子类来修补
MagicMock

with mock.patch('mock.MagicMock', MyMock):
    with mock.patch.object(MyClass, 'my_method', autospec=True,
                           side_effect=MyClass.my_method) as spy:
        ...

演示:https://ideone.com/aKfvek

© www.soinside.com 2019 - 2024. All rights reserved.