在单元测试中模拟Flask的request.get_json时出现“RuntimeError: Working outside of request context”
我正在为一个大型的Flask应用程序的后端开发单元测试。我在测试一个辅助函数get_post_args(),看看它是否能正确处理空请求:
from flask import request
from unittest.mock import patch
from errors import NoPostArguments
def get_post_args() -> Dict[str, Any]:
args = request.get_json()
if not isinstance(args, dict):
raise NoPostArguments(
"no arguments given for this POST request; request not served"
)
return args
def test_get_post_args_returns_none():
with patch(
"request.get_json",
return_value=None,
):
with unittest.TestCase().assertRaises(NoPostArguments):
get_post_args()
当我用pytest运行这个测试时,出现了错误:
test_get_post_args_returns_none failed: def test_get_post_args_returns_none():
> with patch(
"flask.request.get_json",
return_value=None,
):
tests\unit_tests\test_arg_validation.py:243:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
..\..\..\AppData\Local\Programs\Python\Python310\lib\unittest\mock.py:1438: in __enter__
original, local = self.get_original()
..\..\..\AppData\Local\Programs\Python\Python310\lib\unittest\mock.py:1401: in get_original
original = target.__dict__[name]
venv02\lib\site-packages\werkzeug\local.py:311: in __get__
obj = instance._get_current_object()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
def _get_current_object() -> T:
try:
obj = local.get()
except LookupError:
> raise RuntimeError(unbound_message) from None
E RuntimeError: Working outside of request context.
E
E This typically means that you attempted to use functionality that needed
E an active HTTP request. Consult the documentation on testing for
E information about how to avoid this problem.
venv02\lib\site-packages\werkzeug\local.py:508: RuntimeError
有没有人知道怎么正确模拟request.get_json()?
1 个回答
0
Flask 提供了一个叫做 app.test_request_context()
的方法,这个方法可以让你创建任何你需要的假请求环境。在这种情况下,使用模拟工具就显得有些多余了。
最简单的用法是:
# Assuming you're inside a class derived from unittest.TestCase
def test_01_simplest(self):
with your_app.test_request_context(method='POST', json={'message': "Hello!"}):
result = get_post_args()
self.assertIn('message', result)
下面是一个例子,用来测试捕捉 NoPostArguments
,因为 get_json
不一定总是返回一个 dict
:
def test_02_json_not_always_a_dict(self):
with your_app.test_request_context(method='POST', json=[]), \
self.assertRaises(NoPostArguments):
get_post_args()
你可能在表达空的 JSON 请求时遇到过困难。这个问题可以通过传递一些额外的参数来解决,这些参数是为 werkzeug.test.EnvironBuilder
定义的。顺便提一下,在这种情况下,request.get_json()
会首先失败,并抛出 werkzeug.exceptions.BadRequest
。所以,正确的测试应该是这样的:
import werkzeug.exceptions
...
def test_03_empty_json_payload(self):
with your_app.test_request_context(method='POST',
json=None, # may be omitted
content_type="application/json"), \
self.assertRaises(werkzeug.exceptions.BadRequest):
get_post_args()