使用mock修补函数时,可以选择将autospec指定为True:
如果设置autospec = True,则使用spec创建模拟 从被替换的对象。模拟的所有属性也将 具有对象的相应属性的规范 更换。被模拟的方法和函数将有其参数 检查并在使用错误调用时引发TypeError 签名。
(http://www.voidspace.org.uk/python/mock/patch.html)
我想知道为什么这不是默认行为?当然,我们几乎总是希望将错误的参数传递给我们修补的任何函数?
答案 0 :(得分:20)
解释这一点的唯一明确方法是实际引用documentation使用自动显示的缺点以及为什么使用它时应该小心:
然而,这并非没有警告和限制,这就是原因 不是默认行为。为了知道属性是什么 在spec对象上可用,autospec必须内省(访问 属性)规范。当您遍历模拟a上的属性时 相应的遍历原始对象正在发生 引擎盖。如果您的任何推出对象具有属性或描述符 这可能会触发代码执行,然后您可能无法使用 autospec。另一方面,设计对象要好得多 所以内省是安全的[4]。
更严重的问题是,例如属性常见 在 init 方法中创建,而不是在类中存在 所有。 autospec无法知道任何动态创建的属性 将api限制为可见属性。
我认为这里的关键点是注意这一行: autospec无法知道任何动态创建的属性并将api限制为可见属性
因此,为了帮助更明确地说明自动指定中断的示例,从文档中获取的这个示例显示了这一点:
>>> class Something:
... def __init__(self):
... self.a = 33
...
>>> with patch('__main__.Something', autospec=True):
... thing = Something()
... thing.a
...
Traceback (most recent call last):
...
AttributeError: Mock object has no attribute 'a'
正如您所看到的,在创建a
对象时,自动显示并不知道存在创建属性Something
的情况。
通常情况下,对于我自己,我只是模拟补丁并且不要使用autospec,因为这种行为通常符合我的期望。
为实例属性分配值没有任何问题。
请注意以下功能示例:
import unittest
from mock import patch
def some_external_thing():
pass
def something(x):
return x
class MyRealClass:
def __init__(self):
self.a = some_external_thing()
def test_thing(self):
return something(self.a)
class MyTest(unittest.TestCase):
def setUp(self):
self.my_obj = MyRealClass()
@patch('__main__.some_external_thing')
@patch('__main__.something')
def test_my_things(self, mock_something, mock_some_external_thing):
mock_some_external_thing.return_value = "there be dragons"
self.my_obj.a = mock_some_external_thing.return_value
self.my_obj.test_thing()
mock_something.assert_called_once_with("there be dragons")
if __name__ == '__main__':
unittest.main()
所以,我只是说我的测试用例我想确保some_external_thing()
方法不会影响我的unittest的行为,所以我只是将我的实例属性分配给每个{{ 1}}。
答案 1 :(得分:0)
自动指定本身的动作可以执行代码,例如通过调用描述符。
>>> class A:
... @property
... def foo(self):
... print("rm -rf /")
...
>>> a = A()
>>> with mock.patch("__main__.a", autospec=False) as m:
... pass
...
>>> with mock.patch("__main__.a", autospec=True) as m:
... pass
...
rm -rf /
因此,这是默认情况下启用的有问题的功能, 仅选择加入。
答案 2 :(得分:0)
多年后回答我自己的问题-另一个原因是速度。
取决于对象的复杂程度,使用autospec可能会大大降低测试速度。我在修补Django模型时发现了这一点。