什么时候应该在模拟库中使用`autospec = True`?
使用mock.patch
及其变体时,何时应使用autospec=True
?什么时候应该在模拟库中使用`autospec = True`?
一方面,this article警告我们总是使用autospec=True
:
...你应该总是使用
create_autospec
方法和autospec
参数与@patch
和@patch.object
装饰。
在另一方面,autospec
有严重的缺点和局限,如idjaw的答案解释this question。
所以我的问题是:什么时候应该使用autospec=True
或create_autospec
,什么时候我不应该使用它?
恐怕没有使用autospec
可能导致如所提到的文章中描述,测试不破时,他们真的应该打破。然而autospec
有其缺点。我该如何行动?
我可以理解建议执行使用autospec
的动机。
也许下面的内容可以帮助你更清楚地知道你得到了什么,而不是用autospec得到。
简而言之,使用autospec可以确保您在模拟中使用的属性实际上是您正在嘲笑的类的一部分。
所以,用下面的例子中,我会说明一个测试将如何通过技术时,你可能不希望它:
拿这个简单的例子,我们将测试:
class Foo:
def __init__(self, x):
self.x = x
class Bar:
def __init__(self):
self.y = 4
self.c = Foo('potato')
而测试代码:
class TestAutoSpec(unittest.TestCase):
@patch('some_module.Foo')
def test_autospec(self, mock_foo_class):
mock_foo_obj = mock_foo_class.return_value
bar_obj = some_module.Bar()
self.assertTrue(hasattr(bar_obj.c, 'you_should_fail'))
现在,如果你在Foo
类回头看看,你会清晰地看到you_should_fail
显然不是属性。但是,如果你运行这个测试代码,它实际上会通过。这是非常误导。
这是因为如果一个属性不存在于MagicMock
中,它将仍然的类型为MagicMock
。如果您在测试打印type(bar_obj.c.you_should_fail)
,你最终会得到:
<class 'unittest.mock.MagicMock'>
这无疑会导致hasattr
测试通过。如果您再次运行上述测试,除了将修补程序更改为:@patch('some_module.Foo', autospec=True)
,则其将失败,因为它应该。
现在,为了编写一个成功的测试,并且仍然使用autospec = True,只需在模拟测试中根据需要创建属性即可。请记住,这是必要的原因,因为autospec无法知道动态创建的属性,即创建实例时的__init__
。
因此,autospec办法做到这一点,将是:
class TestAutoSpec(unittest.TestCase):
@patch('some_module.Foo', autospec=True)
def test_autospec(self, mock_foo_class):
mock_foo_obj = mock_foo_class.return_value
# create the attribute you need from mocked Foo
mock_foo_obj.x = "potato"
bar_obj = some_module.Bar()
self.assertEqual(bar_obj.c.x, 'potato')
self.assertFalse(hasattr(bar_obj.c, 'poof'))
现在,你的测试将成功通过验证时您x
属性,同时还确认,你也别有一番虚假属性这在您的真实Foo
类中不存在。
这里也是用的Martijn Pieters的,真没必要直接回答你的问题的另一种解释,但给出了一个使用autospec的一个很好的例子和说明,可以帮助您进一步了解: