python - Autospec 模拟没有正确保留签名?
问题描述
根据模拟指南:
自动指定创建的模拟对象与它们要替换的对象具有相同的属性和方法,并且任何函数和方法(包括构造函数)都具有与真实对象相同的调用签名。
但这似乎不是真的。Stdlibinspect
仍然在 mock 上看到一个通用*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)
会正确 raise TypeError: too many positional arguments
,但似乎这是通过调用堆栈中更深的一些代码实现的。它不是通过调用签名完成的。
在您实际依赖签名本身的代码中(并且在测试中模拟时需要保留正确的签名),如何以正确保留签名的方式自动指定模拟?
解决方案
这实际上被认为是 Python 中的一个错误,并已在 Python 3.8 中修复。一个补丁也被反向移植到 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()
遵循属性,如PEP 362中所述:__signature__
如果对象有一个
__signature__
属性,如果没有None
- 返回它
不幸的是,函数或模块的文档中signature()
没有提到这一点。inspect
推荐阅读
- javascript - (index):551 Uncaught ReferenceError: validateText is not defined
- c# - 如何将 mywebsite.com/filename 路由到某些操作方法?
- javascript - 道具类型失败:提供给“图片”的道具“来源”无效
- c++ - 从用户那里获取 10 个整数,然后用户可能会要求显示正数或负数的计数
- swagger - 如何通过openapi中的operationId获取api端点
- spring-boot - 在 Groovy 测试期间 Spring Autowire bean NullPointerException 但在运行时工作正常
- java - Logback 没有创建日志文件
- javascript - React Chart.js 将 API 数据与标题显示的内容匹配,然后根据数据/标题更改更新图表
- python - 基于键附加字典 - 覆盖以前的值
- msal - 使用代码调用acquireToken方法时出现“'openid profile offline_access'无效”错误