了解我自己的装饰师

时间:2014-12-01 16:42:31

标签: python decorator python-decorators httpretty

我写了一个正常工作的装饰器但是我通过反复试验找到了正确的解决方案,而且我对装饰器的知识告诉我某些东西没有明确定义。

案例是我嘲笑Rest Api做一些TDD,而这个Rest是一个令牌安全的背后。因此,在提出任何请求之前,首先必须获取我的用户令牌。我使用httpretty来模拟API。

到目前为止,我必须在每个测试用例中注册register_uri,一个用于模拟/ token资源,另一个用于测试任何其他资源。但我发现这非常麻烦,所以附带一个解决方案来编写一个简单的装饰器来模拟/ token然后只需要模拟测试的资源。

这是我目前正在工作的装饰......

def activate_security(func):
    def test_case(test_case):
        httpretty.enable()
        uri = 'http://{}:{}/token'.format(HOST, PORT)
        httpretty.register_uri(httpretty.GET, uri,
                               body=dumps({'token': 'dummy_token'}),
                               content_type='application/json')
        test_case()
        httpretty.disable()
    return test_case

这就是所谓的。

@activate_security
@httpretty.activate
def test_case_one(self):
    #Test case here

我必须将test_case参数传递给内部函数'因为没有它它不会工作,并且test_case是test_case_one方法,我认为它将在func参数中传递,但是func在外部作用域中将对象保存在test_case的内存中。

是否应该修饰装饰器的返回值?如果我这样做,装饰师不会工作。当内部函数传递那个参数?

1 个答案:

答案 0 :(得分:2)

您正在修饰方法,因此生成的包装函数需要self参数,就像在类中使用的普通函数一样。

所有不同之处在于您为self参数test_case使用了不同的名称。实际上,实例是可调用的,并且调用它会运行测试,因此您实际上正在执行self()以再次运行测试

只需将参数命名为self并将其传递给包装函数:

def activate_security(func):
    def wrapper(self):
        httpretty.enable()
        uri = 'http://{}:{}/token'.format(HOST, PORT)
        httpretty.register_uri(httpretty.GET, uri,
                               body=dumps({'token': 'dummy_token'}),
                               content_type='application/json')
        func(self)
        httpretty.disable()
    return wrapper

然后wrapper()函数替换原始的test_case_one函数,并且在运行测试时,wrapper()函数绑定到测试用例实例,并将该实例作为{{}传递1}};在您的包装器中,您只需将self传递给它即可调用未绑定 func()

出于调试目的,将一些函数属性从包装函数复制到包装器通常更好。 @functools.wraps() decorator可以为您处理这些细节:

self