das*_*s-g 7 python unit-testing mocking python-unittest.mock
当一个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
Run Code Online (Sandbox Code Playgroud)
检查具有相同值的其他签名将失败.例如,如果我们检查'baz'作为位置参数而不是命名参数,则断言将失败:
m.assert_called_once_with('foo', 'baz')
# AssertionError: Expected call: mock('foo', 'baz')
# Actual call: mock('foo', bar='baz')
Run Code Online (Sandbox Code Playgroud)
它必须.如果功能被替换m为
def actual_fu(foo, bar):
# do something
Run Code Online (Sandbox Code Playgroud)
然后调用将是等效的,但如果是的话
def a_different_actual_fu(foo, *args, bar='some default'):
# do something
Run Code Online (Sandbox Code Playgroud)
那么这些电话就不一定了.Mock不知道实际函数的签名,因此它不能依赖于我们在第一种情况下的等价性.
有没有办法通过让Mock(或断言助手函数或类似函数)了解模拟替换的实际函数来检查与它们是通过位置传递还是作为关键字参数无关的调用参数值?
该Mock对象可以知道它所取代的对象(可以是一个函数或方法)与可选的spec参数或autospeccing,但那些用于不同的目的(限制什么叫以允许在模拟),并且不影响以后 - 事实核查.
可以使 Mock 对象知道它替换的对象(可以是函数或方法)使用可选的 spec 参数或使用
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')
Run Code Online (Sandbox Code Playgroud)
现在,看看它是如何通过的,如果我们提供一个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')
>>>
Run Code Online (Sandbox Code Playgroud)
(使用 Python 3.5.1)