Python3.7中Pytest提示‘fixture func未找到’的装饰器问题
为什么Python 3.7下pytest报"fixture 'func' not found",Python 2.7却正常?
问题根源:你写错了functools.update_wrapper的参数
先直接说核心问题:你的装饰器代码里,functools.update_wrapper(wrapper_func, my_decorator)这一行犯了个低级错误——第二个参数应该传入被装饰的原始测试函数func,而不是装饰器本身my_decorator。
为什么Python版本间会有差异?
- Python 2.7环境:pytest 4.6.9在解析测试函数时,可能没有严格校验被装饰后函数的
__wrapped__属性或签名信息。即使你错误地把wrapper的元数据关联到了my_decorator,pytest也没去解析这个装饰器函数的参数(也就是func),所以没触发fixture找不到的错误。 - Python 3.7环境:Python 3对
functools.update_wrapper的元数据复制更彻底,包括函数签名相关的属性。当你把wrapper关联到my_decorator后,pytest会识别到这个"测试函数"的签名是my_decorator(func),误以为test_bla需要一个名为func的fixture,于是抛出错误。
正确的测试函数装饰器写法
有两种可靠的方式,都能让你的装饰器在两个Python版本下兼容:
方式1:修正update_wrapper的参数
import functools def my_decorator(func): def wrapper_func(*args, **kwargs): # 前置操作 ret = func(*args, **kwargs) # 后置操作 return ret # 第二个参数改为原始函数func,正确关联元数据 return functools.update_wrapper(wrapper_func, func) @my_decorator def test_bla(): pass
方式2:使用@functools.wraps(func)(更简洁)
这也是你发现的可行方案,本质上functools.wraps就是update_wrapper的语法糖,自动帮你把wrapper的元数据关联到原始函数:
import functools def my_decorator(func): @functools.wraps(func) def wrapper_func(*args, **kwargs): # 前置操作 ret = func(*args, **kwargs) # 后置操作 return ret return wrapper_func @my_decorator def test_bla(): pass
这两种写法的核心都是让wrapper函数的元数据正确指向原始测试函数,这样pytest就能正常识别测试函数的签名,不会误判需要额外的fixture。
内容的提问来源于stack exchange,提问作者Andreas Maier
相关产品推荐
相关产品推荐

