我应何时在模拟库中使用`autospec = True`?

Avi*_*ohn 4 python unit-testing mocking

autospec=True使用mock.patch及其变体时应何时使用?

一方面,本文警告我们务必使用autospec=True

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

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

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

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

idj*_*jaw 5

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

也许以下内容可以帮助您更清楚地了解使用autospec获得和不获得的内容。

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

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

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

class Foo:
    def __init__(self, x):
        self.x = x

class Bar:
    def __init__(self):
        self.y = 4
        self.c = Foo('potato')
Run Code Online (Sandbox Code Playgroud)

和测试代码:

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'))
Run Code Online (Sandbox Code Playgroud)

现在,如果您回顾一下Foo该类,您将清楚地看到you_should_fail显然不是中的属性Foo。但是,如果您运行此测试代码,则它实际上会通过。这是非常误导的。

这是因为如果一个属性不以存在MagicMock,这将仍然是类型MagicMock。如果type(bar_obj.c.you_should_fail)在该测试中打印,最终将得到:

<class 'unittest.mock.MagicMock'>
Run Code Online (Sandbox Code Playgroud)

这肯定会导致hasattr测试通过。如果您再次运行上述测试,除了改变你的补丁是:@patch('some_module.Foo', autospec=True),它失败,因为它应该。

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

因此,执行此操作的自动规格方式为:

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'))
Run Code Online (Sandbox Code Playgroud)

现在,您的测试将成功通过验证您的x属性,同时还验证您没有真实Foo类中不存在的虚假属性。

这也是Martijn Pieters的另一种解释,它不一定直接回答您的问题,但是提供了一个很好的示例和使用autospec的解释,可以帮助您进一步理解:

/sf/answers/2219700101/