如何在 Pytest 中优雅地链式 Mock 混合同步与异步的上下文管理器调用

冬敏酱_3962

冬敏酱_3962

2026-09-15

1000人浏览

原创

如何在 Pytest 中优雅地链式 Mock 混合同步与异步的上下文管理器调用

本文介绍一种简洁、可读性强的方案,利用 contextlib.nullcontext 统一处理 aiohttp.ClientSession 等混合 sync/async 上下文管理器的链式 Mock,避免冗长中间变量,直接控制最终 await resp.json() 的返回值。

本文介绍一种简洁、可读性强的方案,利用 `contextlib.nullcontext` 统一处理 `aiohttp.clientsession` 等混合 sync/async 上下文管理器的链式 mock,避免冗长中间变量,直接控制最终 `await resp.json()` 的返回值。

在使用 pytest 测试异步 HTTP 客户端(如 aiohttp)时,常见的嵌套异步上下文结构:

async with aiohttp.ClientSession() as session:
    async with session.post("https://example.com") as resp:
        data = await resp.json()

其调用链涉及 同步对象创建ClientSession() 返回 sync 对象)、异步进入上下文__aenter__)、同步方法调用session.post() 返回 ClientResponse 对象)、再次异步进入resp.__aenter__),最后才是 异步方法调用resp.json())。传统 Mock 方式需逐层构造 Mock / AsyncMock 并手动设置 __aenter__ 返回值,代码臃肿且语义模糊:

# ❌ 冗余、易错、意图不清晰
mock_session = Mock()
mock_resp_cm = AsyncMock()
mock_resp = Mock()
mock_resp.json = AsyncMock(return_value={"ok": True})
mock_resp_cm.__aenter__.return_value = mock_resp
mock_session.post.return_value = mock_resp_cm
MockClientSession.return_value.__aenter__.return_value = mock_session

✅ 推荐解法:contextlib.nullcontextAsyncMock “包装”为支持 __aenter__/__aenter__ 的上下文管理器,从而实现链式 .return_value 风格的简洁 Mock。

nullcontext(obj) 是 Python 3.7+ 引入的轻量级上下文管理器,它在 __enter__ 中直接返回 obj,在 __exit__ 中不做任何操作 —— 正好适配 AsyncMock 实例作为 async with 目标的场景。

以下是完整、可运行的测试示例:

import contextlib
import pytest
from unittest import mock
import aiohttp

@pytest.mark.asyncio
async def test_aiohttp_json_mock():
    # ✅ 定义期望响应数据
    expected_data = {"status": "success", "code": 200}

    # ✅ 构建带规范 spec 的 AsyncMock 响应对象,并预设 json() 返回值
    mock_response = mock.AsyncMock(
        spec=aiohttp.ClientResponse,
        **{"json.return_value": expected_data}
    )

    # ✅ 将 mock_response 包装为 async context manager(支持 async with)
    # 同时构建 session.post() 的返回值(即该包装后的响应)
    mock_session = mock.Mock(
        spec=aiohttp.ClientSession,
        **{
            "post.return_value": contextlib.nullcontext(mock_response)
        }
    )

    # ✅ Mock ClientSession 构造函数,使其返回一个支持 async with 的 session
    with mock.patch("aiohttp.ClientSession", return_value=contextlib.nullcontext(mock_session)):
        async with aiohttp.ClientSession() as session:
            async with session.post("https://example.com") as resp:
                result = await resp.json()
                assert result == expected_data

? 关键要点说明

  • contextlib.nullcontext(mock.AsyncMock(...))AsyncMock 兼容 async with 语法,无需手动设置 __aenter__
  • mock.Mock(spec=..., **{...}) 支持字典式属性赋值,使 post.return_value 链式配置更紧凑;
  • 所有 spec= 参数确保类型安全与 IDE 友好(如自动补全、类型检查);
  • 无需显式 patch 模块路径(如 "__main__.aiohttp.ClientSession"),推荐使用 "aiohttp.ClientSession"(注意:实际使用时需根据被测代码中 import aiohttp 的位置调整 patch 路径,通常为模块内引用路径)。

? 进阶提示:若需模拟不同 URL 返回不同响应,可将 mock_session.post 替换为 side_effect 函数,动态返回对应 nullcontext(AsyncMock(...));若需校验请求参数,可断言 mock_session.post.call_args

此方法显著提升异步上下文链式 Mock 的可维护性与表达力,让测试聚焦于「行为预期」而非「Mock 结构」。

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
pycharm怎么改成中文
pycharm怎么改成中文

PyCharm是一种Python IDE(Integrated Development Environment,集成开发环境),带有一整套可以帮助用户在使用Python语言开发时提高其效率的工具,比如调试、语法高亮、项目管理、代码跳转、智能提示、自动完成、单元测试、版本控制。此外,该IDE提供了一些高级功能,以用于支持Django框架下的专业Web开发。php中文网给大家带来了pycharm相关的教程以及文章,欢迎大家前来学习和阅读。

2023.07.25

2329

3

pycharm安装教程
pycharm安装教程

PyCharm是一款由JetBrains开发的Python集成开发环境(IDE),它提供了许多方便的功能和工具。本专题为大家带来pycharm安装教程,帮助大家解决问题。

2023.08.21

4317

4

如何解决pycharm找不到模块
如何解决pycharm找不到模块

解决pycharm找不到模块的方法:1、检查python解释器;2、安装缺失的模块;3、检查项目结构;4、检查系统路径;5、使用虚拟环境;6、重启PyCharm或电脑。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2023.12.04

738

5

如何安装pycharm
如何安装pycharm

安装pycharm的步骤:1、访问PyCharm官方网站下载最新版本的PyCharm;2、下载完成后,打开安装文件;3、安装完成后,打开PyCharm;4、在PyCharm的主界面中等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.02.23

694

5

python和pycharm的区别
python和pycharm的区别

Python和PyCharm是两个不同的概念,它们的区别如下:1、Python是一种编程语言,而PyCharm是一款Python集成开发环境;2、Python可以运行在各种不同的开发环境中,而PyCharm是专门为Python开发而设计的IDE等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.02.23

467

5

pycharm环境如何配置
pycharm环境如何配置

配置教程:1、下载并安装PyCharm;2、选择Python解释器;3、配置虚拟环境;4、配置代码风格;5、配置调试器;6、配置版本控制工具;7、配置插件;8、配置Python路径和环境变量;9、配置其他选项。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.02.23

482

5

pycharm解释器如何安装
pycharm解释器如何安装

安装步骤:1、打开PyCharm并打开你的项目;2、转到"File">“Settings”;3、在设置窗口中选择"Project">“Python Interpreter”;4、 点击“+” 符号添加新的解释器等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.02.23

323

5

pycharm并行运行是啥意思
pycharm并行运行是啥意思

pycharm中的并行运行功能允许并发运行代码块,提高开发和测试效率。通过启用该功能和设置进程数,可以:加快开发和调试过程;缩短测试套件的运行时间;充分利用多核处理器;简化复杂代码的结构和维护。想了解更多pycharm的相关内容,可以阅读本专题下面的文章。

2024.04.18

1128

11

pycharm的作用
pycharm的作用

pycharm是一款专为python编程设计的ide,提供以下功能:智能代码补全,实时错误检测和快速修复;代码重构,版本控制集成,先进调试工具等等。想了解更多pycharm的相关内容,可以阅读本专题下面的文章。

2024.04.18

4776

10

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.6万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 133.1万人学习