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

When should I use `autospec=True` with the mock library?

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

一方面,本文警告我们始终使用autospec=True

... you should always use the create_autospec method and the autospec parameter with the @patch and @patch.object decorators.

另一方面,autospec有严重的缺点和局限性,正如idjaw对这个问题的回答所解释的。

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

我担心不使用autospec可能会导致测试在真正应该中断时不会中断,如本文所述。但是,autospec有其缺点。我该怎么做?


我可以理解建议强制使用autospec的动机。

也许下面的内容可以帮助您更清楚地了解Autospec的优点和缺点。

简而言之,使用autospec可以确保模拟中使用的属性实际上是模拟类的一部分。

因此,通过下面的示例,我将说明当技术上您可能不希望测试通过时,测试将如何通过:

举个简单的例子,我们将测试:

1
2
3
4
5
6
7
8
class Foo:
    def __init__(self, x):
        self.x = x

class Bar:
    def __init__(self):
        self.y = 4
        self.c = Foo('potato')

测试代码:

1
2
3
4
5
6
7
8
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),您将得到:

1
<class 'unittest.mock.MagicMock'>

这肯定会使hasattr测试通过。如果您再次运行上述测试,除了将补丁更改为:@patch('some_module.Foo', autospec=True),它将失败。

现在,要为此编写一个成功的测试并仍然使用autospec=true,只需根据需要在模拟测试中创建属性。请记住,之所以需要这样做,是因为autospec无法了解动态创建的属性,即在创建实例时在__init__中创建的属性。

因此,autospec的方法是:

1
2
3
4
5
6
7
8
9
10
11
12
13
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