根据mock guide:
自动规范创建的模拟对象的属性和方法与要替换的对象相同,并且任何函数和方法(包括构造函数)的调用签名与真实对象相同。 < / p>
但这似乎不是事实。 Stdlib inspect
仍然在模拟中看到通用的*args, **kwargs
签名:
>>> from unittest.mock import patch
>>> def foo(arg1, arg2, arg3):
... pass
...
>>> print(*inspect.signature(foo).parameters)
arg1 arg2 arg3
>>> with patch("__main__.foo", autospec=True) as mock:
... print(*inspect.signature(mock).parameters)
...
args kwargs
autospec可以正常工作,因为mock(1,2,3,4)
将正确地引发TypeError: too many positional arguments
,但是看来这是通过调用堆栈中更深的一些代码实现的。不能通过呼叫签名来完成。
在您实际上依赖签名本身(并且在测试中进行模拟时需要保留正确的签名)的代码中,如何以一种可以正确保留签名的方式自动指定模拟?
答案 0 :(得分:1)
这实际上被认为是Python中的错误,并且已经fixed in Python 3.8。补丁也是backported to Python 3.7.3。相关问题和请求请求:
我遇到了类似的问题,测试了一些代码来检查可笑对象的签名。我通过将模拟的__signature__
属性设置为原始属性来解决了这个问题:
from inspect import signature
from unittest.mock import patch
def foo(a, b, c):
pass
foo_sig = signature(foo) # Need to cache the signature before mocking foo
with patch("__main__.foo") as mock:
mock.__signature__ = foo_sig
print(signature(mock)) # Prints '(a, b, c)'
之所以可行,是因为signature()
函数在尝试其他方法之前遵循__signature__
属性,如PEP 362中所述:
如果对象具有
__signature__
属性,而对象没有None
,则将其返回
不幸的是,the documentation for the signature()
function或inspect
模块中没有提到这一点。