我有一个python模块security.py
它定义了一个装饰器authorized()
。
我想测试装饰器。装饰器将收到烧瓶请求标头。装饰器是这样的:
def authorized():
def _authorized(wrapped_func):
def _wrap(*args, **kwargs):
if 'token' not in request.headers:
LOG.warning("warning")
abort(401)
return None
return wrapped_func(*args, **kwargs)
return _wrap
return _authorized
我想使用@patch
装饰器模拟烧瓶请求标头。我写的测试是这样的:
@patch('security.request.headers', Mock(side_effect=lambda *args, **kwargs: MockHeaders({})))
def test_no_authorization_token_in_header(self):
@security.authorized()
def decorated_func(token='abc'):
return access_token
result = decorated_func()
self.assertEqual(result, None)
class MockHeaders(object):
def __init__(self, json_data):
self.json_data=json_data
但我总是收到以下错误:
name = 'request'
def _lookup_req_object(name):
top = _request_ctx_stack.top
if top is None:
raise RuntimeError(_request_ctx_err_msg)
RuntimeError: Working outside of request context.
This typically means that you attempted to use functionality that needed
an active HTTP request. Consult the documentation on testing for
information about how to avoid this problem.
我应该怎么做?
模拟整个请求对象以避免触发上下文查找:
@patch('security.request')
并从那里建立模拟:
@patch('security.request')
def test_no_authorization_token_in_header(self, mock_request):
mock_request.headers= {}
@security.authorized()
def decorated_func(token='abc'):
return token
self.assertRaises(Abort):
result = decorated_func()
由于缺少令牌会导致引发Abort
异常,因此应显式测试该异常。请注意,request.headers
属性不会在任何地方调用,因此side_effect
或return_value
属性在这里不适用。
我完全忽略了MockHeaders
;你的装饰器没有使用json_data
,你的实现缺乏__contains__
方法,所以in
测试都不起作用。对于当前测试的代码,一个普通的字典就足够了。
旁注:authorized
是一个装饰器工厂,但它不需要任何参数。如果你根本不使用那里的工厂会更清楚。您还应该使用 functools.wraps()
来确保其他修饰器添加的任何元数据都正确传播:
from functools import wraps
def authorized(wrapped_func):
@wraps(wrapped_func)
def _wrap(*args, **kwargs):
if 'token' not in request.headers:
LOG.warning("warning")
abort(401)
return None
return wrapped_func(*args, **kwargs)
return _wrap
然后直接使用装饰器(所以没有调用(:
@security.authorized
def decorated_func(token='abc'):
return access_token