You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

单元测试Mock Flask的request.get_json触发请求上下文外运行错误

问题:Flask单元测试中正确Mock request.get_json()的方法

我正在为大型Flask应用的后端开发单元测试,目的是验证辅助函数get_post_args()能否正确处理空请求,编写的测试代码如下:

from flask import request
from unittest.mock import patch
from typing import Dict, Any

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

请问如何正确mock request.get_json()以解决该问题?


解决方案

错误核心原因:Flask的request是上下文局部对象(Werkzeug的LocalProxy),直接patchflask.request.get_json时,mock会尝试访问真实的request实例,但此时没有激活任何请求上下文,因此抛出Working outside of request context错误。

有两种可靠的解决方式:

方式一:Patch当前模块中导入的request对象

get_post_args函数使用的是从flask导入到当前模块的request对象,因此应该patch该模块内的request.get_json,而非顶层的flask.request.get_json。

假设get_post_args所在模块名为utils.py,修正后的测试代码如下:

import pytest
from unittest.mock import patch

from utils import get_post_args
from errors import NoPostArguments

def test_get_post_args_returns_none():
    # 注意patch路径是目标函数所在模块的request对象
    with patch("utils.request.get_json", return_value=None):
        with pytest.raises(NoPostArguments):
            get_post_args()

方式二:激活Flask请求上下文

通过Flask提供的test_request_context()上下文管理器创建虚拟请求上下文,让request对象能正常被访问,再执行patch操作:

import pytest
from unittest.mock import patch
from flask import Flask

from utils import get_post_args
from errors import NoPostArguments

# 导入你的Flask应用实例,或临时创建一个
app = Flask(__name__)

def test_get_post_args_returns_none():
    with app.test_request_context():
        with patch("flask.request.get_json", return_value=None):
            with pytest.raises(NoPostArguments):
                get_post_args()

额外优化:改用pytest风格断言

原测试中unittest.TestCase().assertRaises的写法不符合pytest规范,建议改用pytest内置的pytest.raises上下文管理器,代码更简洁且适配pytest生态。


内容的提问来源于stack exchange,提问作者Viktor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 09:53:29