我的理解是 MagicMock 是 Mock 的超集,它自动执行“魔术方法”,从而无缝地提供对列表,迭代等的支持......然后是什么是 Mock 存在的原因?这不仅仅是 MagicMock 的精简版,几乎可以被忽略吗? Mock 类是否知道 MagicMock 中没有的任何技巧?
答案 0 :(得分:87)
Mock的作者Michael Foord致辞a very similar question at Pycon 2011 (31:00):
问:为什么MagicMock是一个单独的东西,而不仅仅是将该功能折叠到默认的模拟对象中?
答:一个合理的答案是,MagicMock的工作方式是通过创建新的模拟和预先配置所有这些协议方法 设置它们,所以如果每个新的模拟创建了一堆新的模拟和 将这些设置为协议方法,然后设置所有这些协议方法 创建了一堆更多的模拟并将它们设置在他们的协议方法上, 你有无限的递归...
如果您希望将模拟器作为容器对象访问,该怎么办? 错误 - 你不希望它工作?如果每个模拟都有自动 得到每种协议方法,然后变得更加困难 那。此外,MagicMock为您做了一些预先配置, 设置可能不合适的返回值,所以我想到了 拥有一切拥有一切的便利会更好 预先配置并可供您使用,但您也可以采取普通的 模拟对象,只需配置你想要存在的魔术方法......
简单的答案是:只要使用MagicMock就可以了 你想要的行为。
答案 1 :(得分:43)
使用Mock,可以模拟魔术方法,但你必须定义它们。 MagicMock有"default implementations of most of the magic methods."。
如果您不需要测试任何魔术方法,Mock就足够了,并且不会给您的测试带来太多无关紧要的事情。如果你需要测试很多魔术方法,MagicMock会为你节省一些时间。
答案 2 :(得分:35)
首先,MagicMock
是Mock
的子类。
class MagicMock(MagicMixin, Mock)
因此,MagicMock提供了Mock提供的所有功能。而不是将Mock视为MagicMock的精简版本,将MagicMock视为Mock的扩展版本。这应该解决你关于为什么Mock存在以及Mock在MagicMock上提供什么的问题。
其次,MagicMock提供了许多/大多数魔术方法的默认实现,而Mock没有。有关所提供的魔术方法的更多信息,请参阅here。
提供魔术方法的一些例子:
>>> 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'>
你可以&#34;看&#34;添加到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。否则,坚持模拟。
答案 3 :(得分:9)
这就是python's official documentation 表示:
在大多数这些示例中,Mock和MagicMock类是可互换的。由于MagicMock是功能更强的类,因此默认情况下使用它是明智的。
答案 4 :(得分:0)
我发现了另一种特殊情况,其中简单 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