首页 文章

python通过模拟测试装饰的装饰

提问于
浏览
3

这个问题是对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
  • 使用这个装饰器,没问题,它能很好地完成这项工作 .

  • 测试一个类似的装饰器,它不需要绝对的kwargs,相同的结果 .

  • 但是使用以下模拟测试此装饰器不起作用:

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'关键字参数时,它会返回我正在提出的异常...

有没有人知道如何测试(通过模拟会更好)这样的装饰器由另一个装饰器装饰,需要访问传递给该函数的一个关键字参数?

1 回答

  • 2
    decorated_func = has_permission_from_slug()(func(kwarg=self.kwarg))
    

    这将:

    • 执行 func(kwarg=self.kwarg)

    • 生成实际装饰器的实例 .

    • 在func- call 的结果上调用装饰器(即结果) .

    • 返回包装器,稍后将尝试调用步骤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异常 .

相关问题