遇到问题:
因为本人之前是用的unittest框架写的自动化脚本,已经预先写好了log日志模块的装饰器。后需将unittest替换成pytest,用到了pytest中功能强大的fixture,但是读取coftest.py中的fixture后,pytest的测试用例中填写fixture的方法名,执行,却发现自己写log装饰器报missing 1 required positional argument
-
同时使用fixture和装饰器代码:
-
报错:
解决问题途径:
发现同样的情况下,加上@allure.step("")装饰器却不会报该错,查看allure的源码
解决问题:
allure源码中,发现装饰器中加了一个@wraps(func),解决上述问题
以下介绍wraps相关:
Python中被装饰后的函数,函数名等函数属性会发生改变(相当于另一个函数了),所以,Python的functools包中提供了一个叫wraps的装饰器来解决该问题。它能使其保留原有函数的结构。
- 不加@wraps()的装饰器:
import time
class MyLog(object):
def __call__(self, func):
def my_log(*args, **kwargs):
"""这里是my_log的docstring"""
start = time.time()
res = func(*args, **kwargs)
end = time.time()
print('|运行时长:{:.4f}'.format(end - start))
return res
return my_log
@MyLog()
def is_test():
"""这里是is_test的docstring"""
print("一个测试方法")
print("__name__: ", is_test.__name__)
print("__doc__: ", is_test.__doc__)
运行结果:
看运行结果,会发现,被装饰器装饰后的函数,name和docstring都发生了变化
- 加了@wraps()的装饰器:
import time
from functools import wraps
class MyLog(object):
def __call__(self, func):
@wraps(func)
def my_log(*args, **kwargs):
"""这里是my_log的docstring"""
start = time.time()
res = func(*args, **kwargs)
end = time.time()
print('|运行时长:{:.4f}'.format(end - start))
return res
return my_log
@MyLog()
def is_test():
"""这里是is_test的docstring"""
print("一个测试方法")
print("__name__: ", is_test.__name__)
print("__doc__: ", is_test.__doc__)
运行结果:
看运行结果,会发现,装饰器加了@wraps后,被装饰器装饰后的函数,还是保持原有的状态
- 装饰器的作用: 在不改变原有功能代码的基础上,添加额外的功能。
- @wraps(func)的作用: 不改变使用装饰器原有函数的结构(如name, doc)