使用autospec=True
及其变体时,我应该何时使用mock.patch
?
一方面,this article警告我们始终使用autospec=True
:
...您应始终使用
create_autospec
方法和autospec
参数与@patch
和@patch.object
装饰器。
另一方面,autospec
有严重的缺点和限制,正如idjaw对this question的回答中所解释的那样。
所以我的问题是:我应该何时使用autospec=True
或create_autospec
,何时不应该使用它?
我担心不使用autospec
可能导致测试在真正破坏时不会破坏,如上所述。但autospec
有其缺点。我该怎么做?
答案 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可以帮助你进一步理解: