问题描述
在使用 mock.patch
及其变体时,我什么时候应该使用 autospec=True
?
When should I use autospec=True
when using mock.patch
and its variants?
一方面,这篇文章警告我们始终使用 autospec=True
:
On one hand, this article warns us to always use autospec=True
:
...你应该总是使用 create_autospec
方法和 autospec
参数与 @patch
和 @patch.object
装饰器.
另一方面,autospec
有严重的缺点和限制,如 idjaw 对 这个问题.
On the other hand, autospec
has serious drawbacks and limits, as explained in idjaw's answer to this question.
所以我的问题是:我什么时候应该使用 autospec=True
或 create_autospec
,什么时候不应该使用它?
So my question is: when should I use autospec=True
or create_autospec
, and when should I not use it?
我担心不使用 autospec
可能会导致测试在真正应该中断的时候没有中断,如上述文章中所述.然而,autospec
有其缺点.我该怎么做?
I fear not using autospec
may result in tests not breaking when they really should break, as described in the mentioned article. However autospec
has its drawbacks. How should I act?
推荐答案
我能理解建议强制使用 autospec
的动机.
I can understand the motivation to suggest the enforcing of using autospec
.
也许以下内容可以帮助您更清楚地了解使用 autospec 会得到什么和不会得到什么.
Maybe the following could help provide more clarity on what you get and don't get with autospec.
简而言之,使用 autospec 可确保您在模拟中使用的属性实际上是您模拟的类的一部分.
In short, using autospec ensures that the attributes you use in your mock are in fact part of the class you are mocking.
因此,通过下面的示例,我将说明在技术上您可能不希望测试通过时如何通过:
So, with the example below, I'll illustrate how a test will pass when technically you might not want it to:
以我们将要测试的这个简单示例为例:
Take this simple example we will test:
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
中的一个属性.但是,如果您运行此测试代码,它实际上会通过.这是非常具有误导性的.
Now, if you look back at the Foo
class, you will clearly see you_should_fail
is clearly not an attribute in Foo
. However, if you run this test code, it will in fact pass. Which is very misleading.
这是因为如果一个属性在 MagicMock
中不存在,它会仍然是 MagicMock
类型.如果您在该测试中打印 type(bar_obj.c.you_should_fail)
,您最终会得到:
This is because if an attribute does not exist in a MagicMock
, it will still be of type MagicMock
. If you print type(bar_obj.c.you_should_fail)
in that test, you will end up getting:
<class 'unittest.mock.MagicMock'>
这肯定会导致 hasattr
测试通过.如果你再次运行上面的测试,除了将你的补丁更改为:@patch('some_module.Foo', autospec=True)
,它将会失败.
This will certainly cause the hasattr
test to pass. If you run the above test again, except change your patch to be: @patch('some_module.Foo', autospec=True)
, it will fail as it should.
现在,要为此编写成功的测试并仍然使用 autospec=True,您只需根据需要在模拟测试中创建属性.请记住,之所以需要这样做,是因为 autospec 无法知道动态创建的属性,即在创建实例时在 __init__
中.
Now, to write a successful test for this and still use autospec=True, you simply create the attribute in your mock testing as needed. Remember, the reason this is needed, is because autospec cannot know about the attributes created dynamically, i.e. in the __init__
when you create an instance.
因此,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
中不存在的虚假属性班级.
Now, your test will successfully pass at validating your x
attribute, while also validating that you don't have some bogus attribute that does not exist in your real Foo
class.
这里还有 Martijn Pieters 的另一种解释,它不一定直接回答您的问题,但提供了一个非常好的示例和使用 autospec 的解释,可以帮助您进一步理解:
Here is also another explanation by Martijn Pieters, that does not necessarily directly answer your question, but gives a very good example and explanation of using autospec that can help further your understanding:
https://stackoverflow.com/a/31710001/1832539
这篇关于我什么时候应该在模拟库中使用 `autospec=True`?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!