繁体   English   中英

了解我自己的装饰器

[英]Understanding my own decorator

我编写的装饰器工作正常,但是由于反复试验,偶然发现了正确的解决方案,而我对装饰器的不屑一顾的知识告诉我,定义不明确的东西。

案例是我正在模拟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的内存。

不应该将装饰器的返回值用作func吗? 如果我这样做,装饰器将无法正常工作。 当内部函数传递该参数时?

您正在修饰方法,因此生成的包装器函数需要一个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()函数将绑定到测试用例实例,并将作为self传递给该实例; 在包装器中,您只需将self传递给未绑定的 func()即可。

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

import functools

def activate_security(func):
    @functools.wraps(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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM