我试图测试下面的装饰器test_params进行单元测试,但是当我尝试在函数test_testparams中调用它时,出现错误:
TypeError: wrapper() takes exactly 1 argument (0 given)
是因为它期待自己吗?
import unittest
import functools
def test_params(kwargs_lst):
'''allows to parametrise tests easily using a decorator'''
def decorator(fn):
@functools.wraps(fn)
def wrapper(self):
for kwargs in kwargs_lst:
fn(self, **kwargs)
return wrapper
return decorator
TEST_PARAMS_ARGS = [
{'arg1': 1, 'arg2': None, 'arg3': "test"},
]
RECORDER = []
class TestParamsClass(object):
def record_args(self, arg1, arg2, arg3):
RECORDER.append({'arg1': arg1, 'arg2': arg2, 'arg3': arg3})
class DecoratorTest(unittest.TestCase):
def setUp(self):
pass
def test_testparams(self):
obj = TestParamsClass()
decorated_fn = test_params(TEST_PARAMS_ARGS)(obj.record_args)
decorated_fn()
print("RECORDED:{}".format(RECORDER))
为全面披露,我已经尝试过传递self参数:
decorated_fn(obj)
但这会给出此错误:
TypeError: record_args() got multiple values for keyword argument 'arg1'
我也尝试使用:
from functools import partial
decorated_fn = test_params(TEST_PARAMS_ARGS)(partial(obj.record_args, self=obj))
这给了我错误:
AttributeError: 'functools.partial' object has no attribute '__module__'
有一个自变量的原因是,它通常在测试函数中用于传递参数,并且测试函数位于unittest.TestCase内部。
答案 0 :(得分:1)
这与what Python methods really are有关。
通常,您将装饰器应用于类声明中的函数,即:
class TestParamsClass(object):
@test_params(TEST_PARAMS_ARGS)
def record_args(self, arg1, arg2, arg3):
RECORDER.append({'arg1': arg1, 'arg2': arg2, 'arg3': arg3})
在这种情况下,test_params
(或更确切地说是内部decorator
函数)将收到record_args
函数作为参数。但是这里:
decorated_fn = test_params(TEST_PARAMS_ARGS)(obj.record_args)
您要传递的是一个Method
对象(请参见上面的链接),该__call__
方法将在调用{{时将obj
作为self
参数注入1}}功能。
如果您的record_args()
装饰器应专门用于方法(或更确切地说,仅用于方法的函数),则可以更改测试以装饰该方法的功能:>
test_param
当然还有手动传递decorated_fn = test_params(TEST_PARAMS_ARGS)(obj.record_args.__func__)
作为参数:
obj
否则,如果您想同时在函数和方法上使用此修饰符,则可以将内部decorated_fn(obj)
函数签名从wrapper
更改为self
(并将其传递给*args
,因此可以适应两种情况。