【问题标题】:What's the difference between mock.MagicMock(spec=SomeClass) and mock.create_autospec(SomeClass)?mock.MagicMock(spec=SomeClass) 和 mock.create_autospec(SomeClass) 有什么区别?
【发布时间】:2020-08-21 19:02:14
【问题描述】:

我正在尝试了解这两种模拟构造之间的区别,以及何时适合使用其中任何一种。我在解释器中对其进行了测试,例如:

>>> mm = mock.MagicMock(spec=list)
>>> ca = mock.create_autospec(list)
>>> mm
<MagicMock spec='list' id='140372375801232'>
>>> mm()
<MagicMock name='mock()' id='140372384057808'>
>>> mm.append()
<MagicMock name='mock.append()' id='140372375724720'>
>>> mm().append()
<MagicMock name='mock().append()' id='140372375753104'>
>>> ca
<MagicMock spec='list' id='140372384059248'>
>>> ca()
<NonCallableMagicMock name='mock()' spec='list' id='140372384057040'>
>>> ca.append()
<MagicMock name='mock.append()' id='140372375719744'>
>>> ca().append()
<MagicMock name='mock().append()' id='140372375796848'>
>>> 

但我不明白为什么“构造”使用create_autospec 创建的模拟会给我一个NonCallableMagicMockMagicMock 给我更多MagicMockdocumentation 没有多大帮助。

【问题讨论】:

  • 你看过documentation吗?
  • 是的,但这并不能帮助我理解差异:)

标签: python mocking python-unittest


【解决方案1】:

使用spec 参数和使用create_autospec 的主要区别在于递归性。在第一种情况下,对象本身是指定的,而被调用的对象不是:

>>> mm = mock.MagicMock(spec=list)
>>> mm
<MagicMock spec='list' id='2868486557120'>
>>> mm.foo
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "c:\Python\Python38\lib\unittest\mock.py", line 635, in __getattr__
    raise AttributeError("Mock object has no attribute %r" % name)
AttributeError: Mock object has no attribute 'foo'
>>> mm.append
<MagicMock name='mock.append' id='2868486430240'>
>>> mm.append.foo
<MagicMock name='mock.append.foo' id='2868486451408'>

在第二种情况下,被调用的对象也被指定(懒惰地):

>>> ca = mock.create_autospec(list)
>>> ca
<MagicMock spec='list' id='2868486254848'>
>>> ca.foo
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "c:\Python\Python38\lib\unittest\mock.py", line 635, in __getattr__
    raise AttributeError("Mock object has no attribute %r" % name)
AttributeError: Mock object has no attribute 'foo'
>>> ca.append
<MagicMock name='mock.append' spec='method_descriptor' id='2868486256336'>
>>> ca.append.foo
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "c:\Python\Python38\lib\unittest\mock.py", line 635, in __getattr__
    raise AttributeError("Mock object has no attribute %r" % name)
AttributeError: Mock object has no attribute 'foo'

有一个警告,如您的示例代码所示。如果您使用create_autospec,如此处所示,它的行为就好像该对象是一个类,而不是一个实例,因此您可以调用它(创建一个实例):

>>> ca = mock.create_autospec(list)
>>> ca()
<NonCallableMagicMock name='mock()' spec='list' id='2868485877280'>

如果你想让它表现得像一个实例,你必须使用instance=True

>>> ca = mock.create_autospec(list, instance=True)
>>> ca
<NonCallableMagicMock spec='list' id='2868485875024'>
>>> ca()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'NonCallableMagicMock' object is not callable

请注意,将mock.patchautospec=True 一起使用会创建一个模拟,其行为类似于使用mock.create_autospec 创建的模拟,如documentation 中所述。

还要注意,调用的返回值始终是MagicMock,无论实际调用的返回值如何。因此,即使函数返回 None,如 list.append,如果从模拟中调用该方法,也会返回模拟,而不管规范如何。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-06-27
    • 2021-10-01
    • 2013-07-27
    • 1970-01-01
    • 1970-01-01
    • 2020-06-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多