Mocking Flask 的 request.get_json 在单元测试中引发“RuntimeError:在请求上下文之外工作”

问题描述 投票:0回答:1

我为大型烧瓶应用程序的后端开发单元测试。我正在测试辅助函数 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() 有什么想法吗?

python unit-testing flask
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',
                                       content_type="application/json"), \
           self.assertRaises(werkzeug.exceptions.BadRequest):
        get_post_args()
© www.soinside.com 2019 - 2024. All rights reserved.