使用 unittest.mock.patch 时,为什么默认情况下 autospec 不是 True?

新手上路,请多包涵

使用 mock 修补函数时,您可以选择将 autospec 指定为 True:

如果您设置 autospec=True 则模拟将使用来自被替换对象的规范创建。模拟的所有属性也将具有被替换对象的相应属性的规范。被模拟的方法和函数将检查其参数,如果使用错误的签名调用它们,将引发 TypeError。

( http://www.voidspace.org.uk/python/mock/patch.html )

我想知道为什么这不是默认行为?当然,我们几乎总是希望捕捉到将不正确的参数传递给我们修补的任何函数?

原文由 seddonym 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 814
2 个回答

解释这一点的唯一明确方法是实际引用有关使用自动指定的 缺点文档 以及为什么在使用它时要小心:

然而,这并非没有警告和限制,这就是为什么它不是默认行为的原因。为了知道规范对象上有哪些属性可用,autospec 必须内省(访问属性)规范。当您遍历 mock 上的属性时,原始对象的相应遍历正在发生。如果您指定的任何对象具有可以触发代码执行的属性或描述符,那么您可能无法使用自动指定。另一方面,最好设计你的对象,这样内省是安全的 [4]。

一个更严重的问题是,在 init 方法中创建实例属性并且根本不存在于类中是很常见的。 autospec 不知道任何动态创建的属性并将 api 限制为可见属性。

我认为这里的关键要点是注意这一行: autospec can’t know about any dynamically created attributes and restricts the api to visible attributes

因此,为了帮助更明确地说明自动指定中断的示例,这个取自文档的示例显示了这一点:

 >>> 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'

如您所见,自动指定不知道在创建 Something 对象时创建了一个属性 a

为您的实例属性赋值没有错。

观察以下功能示例:

 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() 方法不会影响我的单元测试的行为,所以我只是将我的实例属性分配给模拟 mock_some_external_thing.return_value = "there be dragons"

原文由 idjaw 发布,翻译遵循 CC BY-SA 4.0 许可协议

多年后回答我自己的问题 - 另一个原因是速度。

根据对象的复杂程度,使用 autospec 可能会显着降低测试速度。我在修补 Django 模型时发现了这一点。

原文由 seddonym 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题