根据mock guide :
Auto-speccing creates mock objects that have the same attributes and methods as the objects they are replacing, and any functions and methods (including constructors) have the same call signature as the real object.
但这似乎不是真的。标准库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: 位置参数太多
,但似乎这是通过调用堆栈中更深处的一些代码实现的。这不是通过调用签名完成的。
在实际依赖签名本身的代码中(并且需要在测试中模拟时保留正确的签名),如何以正确保留签名的方式自动指定模拟?
最佳答案
这实际上被认为是 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 中所述。 :
If the object has a
__signature__
attribute and if it is notNone
- return it
不幸的是,the documentation for the signature()
function 中没有提到这一点。或inspect
模块。
关于python - Autospec 模拟未正确保留签名?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54099582/