我有一个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.
我该怎么做?
答案 0 :(得分:3)
模拟整个请求对象以避免触发上下文查找:
@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