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

时间:2016-11-09 03:13:07

标签: python unit-testing mocking

使用autospec=True及其变体时,我应该何时使用mock.patch

一方面,this article警告我们始终使用autospec=True

  

...您应始终使用create_autospec方法和autospec参数与@patch@patch.object装饰器。

另一方面,autospec有严重的缺点和限制,正如idjaw对this question的回答中所解释的那样。

所以我的问题是:我应该何时使用autospec=Truecreate_autospec,何时不应该使用它?

我担心不使用autospec可能导致测试在真正破坏时不会破坏,如上所述。但autospec有其缺点。我该怎么做?

1 个答案:

答案 0 :(得分:3)

我可以理解建议强制使用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显然不是Foo中的属性。但是,如果您运行此测试代码,它实际上将通过。这是非常误导的。

这是因为如果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