9

当一个unittest.mock.Mock对象被调用时,我可以使用调用的确切签名检查参数值:

from unittest.mock import Mock

m = Mock()  # creation of mock
m('foo', bar='baz')  # call to the mock
m.assert_called_once_with('foo', bar='baz')  # check call arguments

检查具有相同值的不同签名将失败。例如,如果我们将 with'baz'作为位置参数而不是命名参数进行检查,则断言将失败:

m.assert_called_once_with('foo', 'baz')
# AssertionError: Expected call: mock('foo', 'baz')
# Actual call: mock('foo', bar='baz')

它必须。如果被替换的函数m

def actual_fu(foo, bar):
    # do something

那么调用将是等效的,但如果是

def a_different_actual_fu(foo, *args, bar='some default'):
    # do something

那么电话将不等价。Mock不知道实际函数的签名,所以它不能依赖我们在第一种情况下的等价性。

有没有一种方法可以通过让 Mock(或断言辅助函数或类似函数)知道被模拟替换的实际函数来检查调用参数值,这些值是按位置传递还是作为关键字参数传递的?

可以使用可选参数或使用autospeccing使对象知道它替换的Mock对象(可以是函数或方法),但它们用于不同的目的(限制在模拟上允许的调用)并且不影响之后- 事实检查。spec

4

1 回答 1

7

可以使用可选的 spec 参数或 with 使 Mock 对象知道它替换的对象(可以是函数或方法)autospeccing,但它们的用途不同。

这正是问题 17015:模拟可以更智能并检查规范的签名改进问题。spec实际上是非常相关的,现在使模拟函数签名感知。

看看当我们断言 mock 是用关键字参数调用时,mock 是如何失败的——而不让它知道实际的函数签名:

>>> from unittest.mock import Mock
>>>
>>> def actual_fu(foo, bar):
...     pass
>>>
>>> m = Mock()
>>> m('foo', bar='baz')
<Mock name='mock()' id='4356741496'>
>>>
>>> m.assert_called_once_with(foo='foo', bar='baz')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/unittest/mock.py", line 803, in assert_called_once_with
    return self.assert_called_with(*args, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/unittest/mock.py", line 792, in assert_called_with
    raise AssertionError(_error_message()) from cause
AssertionError: Expected call: mock(bar='baz', foo='foo')
Actual call: mock('foo', bar='baz')

现在,看看如果我们提供一个spec

>>> m = Mock(spec=actual_fu)
>>> m('foo', bar='baz')
<Mock name='mock()' id='4356249528'>
>>> 
>>> m.assert_called_once_with(foo='foo', bar='baz')
>>> m.assert_called_once_with('foo', bar='baz')
>>> m.assert_called_once_with(bar='baz', foo='foo')
>>> m.assert_called_once_with('foo', 'baz')
>>>

(使用 Python 3.5.1)

于 2016-03-30T16:17:21.837 回答