什么时候应该在模拟库中使用`autospec = True`?

问题描述:

使用mock.patch及其变体时,何时应使用autospec=True什么时候应该在模拟库中使用`autospec = True`?

一方面,this article警告我们总是使用autospec=True

...你应该总是使用create_autospec方法和autospec参数与@patch@patch.object装饰。

在另一方面,autospec有严重的缺点和局限,如idjaw的答案解释this question

所以我的问题是:什么时候应该使用autospec=Truecreate_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的一个很好的例子和说明,可以帮助您进一步了解:

https://stackoverflow.com/a/31710001/1832539