试图绕过Spec和Autospec之间的区别。他们似乎差不多。具体来说,如果你看一下mock.patch装饰。
有人可以解释何时使用哪个?
答案 0 :(得分:2)
spec
用作Mock对象的模板。用documentation:
如果使用spec或spec_set参数,则只会创建规范中存在的魔术方法。
这意味着您无法在模拟对象上调用您正在模拟的对象上不存在的方法。 documentation解释如下:
注意如果使用spec关键字参数创建模拟,那么尝试设置不在规范中的魔术方法将引发AttributeError。
autospec
基本上是patch
中的简写,用于将修补的对象传递给正在创建的spec
的{{1}}。文档:
如果设置autospec = True,则使用要替换的对象的规范创建模拟。
答案 1 :(得分:1)
spec
仅适用于指定了它的模拟实例。特别是,如果模拟的类a
具有方法,例如method()
,然后在实例化的a
中调用该方法将自动生成并返回另一个不受任何规范限制的模拟。这是autospec
派上用场的地方,因为它递归地定义了所调用内容的规范(在此之前所定义的规范的限制内)。
来自Mock Autospeccing Helper documentation:
如果您使用类或实例作为模拟的规范,则只能访问真实类中存在的模拟属性:
>>> import urllib2
>>> mock = Mock(spec=urllib2.Request)
>>> mock.assret_called_with
Traceback (most recent call last):
...
AttributeError: Mock object has no attribute 'assret_called_with'
该规范仅适用于模拟本身,因此模拟上的任何方法仍然存在相同的问题:
>>> mock.has_data()
<mock.Mock object at 0x...>
>>> mock.has_data.assret_called_with()
自动配置解决了此问题。
答案 2 :(得分:0)
我将在unittest.mock.patch上对其进行解释,因为它有两个选项spec
,它们有望成为模拟和autospec
的规范对象,类似于spec,除了它将为spec对象的所有“子”模拟提供规范,以下是这些用例的说明:
from unittest.mock import Mock, create_autospec, patch
from unittest import TestCase
class MyClass:
@staticmethod
def method(foo, bar):
print(foo)
def some_method(some_class: MyClass):
arg = 1
# Would fail because of wrong parameters passed to method.
return some_class.method(arg)
class TestSomethingTestCase(TestCase):
def test_something_with_patch_spec(self):
with patch(f'{__name__}.MyClass', spec=True) as mock:
# Fails because of signature misuse.
result = some_method(mock)
self.assertTrue(result)
self.assertTrue(mock.method.called)
def test_second_with_patch_autospec(self):
with patch(f'{__name__}.MyClass', autospec=True) as mock:
# Fails because of signature misuse.
result = some_method(mock)
self.assertTrue(result)
self.assertTrue(mock.method.called)
具有自动spec的测试用例将捕获代码中的错误,因为MyClass.method
签名与some_method
上预期的签名不对应,而预期的test_something_with_patch_spec
对应会给您误报,因此测试无法履行其职责。
unittest.mock.Mock仅具有spec选项,作为替代方案,您可以使用unittest.mock.create_autospec,因此它将创建具有上述示例中所述的autospec效果的Mock。