My understanding is that MagicMock is a superset of Mock that automatically does "magic methods" thus seamlessly providing support for lists, iterations and so on... Then what is the reason for plain Mock existing? Isn't that just a stripped down version of MagicMock that can be practically ignored? Does Mock class know any tricks that are not available in MagicMock?
5 回答
普通Mock存在的原因是什么?
Mock 的作者 Michael Foord在 Pycon 2011 (31:00) 上解决了一个非常相似的问题:
问:为什么 MagicMock 做了一个单独的东西,而不是将能力折叠到默认的模拟对象中?
答:一个合理的答案是,MagicMock 的工作方式是它通过创建新的 Mocks 并设置它们来预先配置所有这些协议方法,所以如果每个新的模拟都创建了一堆新的模拟并将它们设置为协议方法,然后所有这些协议方法创建了更多的模拟并将它们设置在他们的协议方法上,你有无限递归......
如果您希望将您的模拟作为容器对象访问是一个错误——您不希望它起作用怎么办?如果每个 mock 都自动获取了每个协议方法,那么做到这一点就变得更加困难。而且,MagicMock 会为您进行一些预配置,设置可能不合适的返回值,所以我认为最好有一个方便的,它已经为您预先配置了所有内容,但您也可以使用普通的模拟对象,只需配置您想要存在的魔术方法...
简单的答案是:如果这是您想要的行为,只需在任何地方使用 MagicMock。
使用 Mock 您可以模拟魔术方法,但您必须定义它们。MagicMock 具有“大多数魔术方法的默认实现”。.
如果您不需要测试任何魔术方法,Mock 就足够了,并且不会在您的测试中带来很多无关紧要的东西。如果您需要测试很多魔术方法,MagicMock 会为您节省一些时间。
首先,MagicMock
是 的子类Mock
。
class MagicMock(MagicMixin, Mock)
因此,MagicMock 提供了 Mock 提供的一切以及更多。与其将 Mock 视为 MagicMock 的精简版本,不如将 MagicMock 视为 Mock 的扩展版本。这应该解决您关于 Mock 存在的原因以及 Mock 在 MagicMock 之上提供什么的问题。
其次,MagicMock 提供了许多/大多数魔术方法的默认实现,而 Mock 没有。有关所提供的魔术方法的更多信息,请参见此处。
提供的魔术方法的一些示例:
>>> int(Mock())
TypeError: int() argument must be a string or a number, not 'Mock'
>>> int(MagicMock())
1
>>> len(Mock())
TypeError: object of type 'Mock' has no len()
>>> len(MagicMock())
0
这些可能不那么直观(至少对我来说不直观):
>>> with MagicMock():
... print 'hello world'
...
hello world
>>> MagicMock()[1]
<MagicMock name='mock.__getitem__()' id='4385349968'>
当这些方法第一次被调用时,您可以“看到”添加到 MagicMock 的方法:
>>> magic1 = MagicMock()
>>> dir(magic1)
['assert_any_call', 'assert_called_once_with', ...]
>>> int(magic1)
1
>>> dir(magic1)
['__int__', 'assert_any_call', 'assert_called_once_with', ...]
>>> len(magic1)
0
>>> dir(magic1)
['__int__', '__len__', 'assert_any_call', 'assert_called_once_with', ...]
那么,为什么不一直使用 MagicMock 呢?
回到你的问题是:你对默认的魔术方法实现还好吗?例如,mocked_object[1]
不出错可以吗?由于魔术方法实现已经存在,您是否可以接受任何意外后果?
如果这些问题的答案是肯定的,那么请继续使用 MagicMock。否则,坚持模拟。
这是python的官方文档 所说的:
在大多数这些示例中,Mock 和 MagicMock 类是可以互换的。由于 MagicMock 是功能更强大的类,因此默认使用它是明智的。
我发现了另一种特殊情况,其中simple Mock
可能比以下更有用MagicMock
:
In [1]: from unittest.mock import Mock, MagicMock, ANY
In [2]: mock = Mock()
In [3]: magic = MagicMock()
In [4]: mock.foo == ANY
Out[4]: True
In [5]: magic.foo == ANY
Out[5]: False
比较ANY
可能很有用,例如,比较两个字典之间的几乎每个键,其中一些值是使用模拟计算的。
如果您正在使用,这将是有效的Mock
:
self.assertDictEqual(my_dict, {
'hello': 'world',
'another': ANY
})
AssertionError
如果您使用过,它会引发MagicMock