这个问题是对Python中装饰器this brilliant answer的后续跟进:
我使用给定的“代码片段使任何装饰器一般接受任何参数”。
然后我有这个(这里是简化的)装饰者:
@decorator_with_args
def has_permission_from_kwarg(func, *args, **kwargs):
"""Decorator to check simple access/view rights by the kwarg."""
def wrapper(*args_1, **kwargs_1):
if 'kwarg' in kwargs_1:
kwarg = kwargs_1['kwarg']
else:
raise HTTP403Error()
return func(*args_1, **kwargs_1)
return wrapper
但是使用以下模拟测试此装饰器不起作用:
def test_can_access_kwarg(self):
"""Test simple permission decorator."""
func = Mock(return_value='OK')
decorated_func = has_permission_from_slug()(func(kwarg=self.kwarg))
# It will raise at the following line, whereas the kwarg is provided...
response = decorated_func()
self.assertTrue(func.called)
self.assertEqual(response, 'OK')
当我没有'kwarg'关键字参数时,它会返回我正在提出的异常......
有没有人知道如何测试(通过模拟会更好)这样的装饰器由另一个装饰器装饰,需要访问传递给函数的一个关键字参数?
答案 0 :(得分:2)
decorated_func = has_permission_from_slug()(func(kwarg=self.kwarg))
这将:
func(kwarg=self.kwarg)
返回包装器,稍后将尝试调用步骤3中的结果(这将失败)。
response = decorated_func()
然后,这将调用返回的包装器,不带参数,因此**kwargs_1
为空。此外,如果您在这种情况下包装器不会引发异常,则后续调用func(..)
会抛出异常,因为func
(原始的)的返回值可能无法调用(参见上文) )。
你可能想要做的事情,或者至少你的装饰者支持的是:
decorated_func = has_permission_from_kwarg()(func)
response = decorated_func(kwarg=self.kwarg)
或者,如果您想在装饰器中传递kwarg
,请执行以下操作:
decorated_func = has_permission_from_kwarg(kwarg=self.kwarg)(func)
response = decorated_func()
然后你需要调整或装饰来实际使用kwargs
,而不是kwargs_1
在检查中(后者是装饰函数的参数)。
我正在使用以下代码测试您的原始装饰器定义(没有更改)和链接答案中定义的decorator_with_args
:
class HTTP403Error (Exception):
pass
def func (*args, **kwargs):
print('func {}; {}'.format(args, kwargs))
my_kwarg = 'foo'
decorated_func = has_permission_from_kwarg()(func)
decorated_func(kwarg=my_kwarg)
decorated_func(not_kwarg=my_kwarg)
正如预期的那样,我为第一次调用打印func (); {'kwarg': 'foo'}
,为第二次调用打印HTTP403异常。