mock上下文管理器时必须显式配置__enter__和__exit__,因Mock默认不实现上下文协议;__enter__需设return_value(如资源对象),__exit__通常返回False或None;patch类时要设return_value为已配好协议的mock实例,patch对象则用patch.object修改其特殊方法。

mock一个上下文管理器对象时,__enter__ 和 __exit__ 必须显式配置
直接用 Mock() 或 patch() 替换类,但没设 __enter__ 返回值,测试会报 AttributeError: __enter__。因为 Mock 默认不实现上下文协议,得手动补上。
-
__enter__通常返回要使用的资源对象(比如数据库连接、文件句柄),可设为return_value或用side_effect控制多次调用行为 -
__exit__一般返回False(表示不吞异常),除非你明确想模拟异常被静默处理;不用设return_value,直接用return_value = None或留空(默认返回None)即可 - 若被 mock 的是实例方法(如
obj.open()返回上下文对象),则需 mock 返回值本身具备上下文能力,而不是只 mockopen
用 patch 模拟类构造后返回带上下文的实例
常见场景:模块中某类被实例化并用于 with 语句,例如 with DatabaseConnection() as db:。这时要 patch 类本身,再配置其返回实例的行为。
from unittest.mock import Mock
import pytest
<p>def test_with_database(mocker):
mock_conn = Mock()
mock_conn.<strong>enter</strong>.return_value = mock_conn # or return a different object
mock_conn.<strong>exit</strong>.return_value = False</p><pre class='brush:python;toolbar:false;'>mocker.patch('my_module.DatabaseConnection', return_value=mock_conn)
# 被测函数内部执行 with DatabaseConnection() as ...
result = my_module.use_db()注意:mocker.patch 的路径必须和运行时导入路径一致(比如 my_module.DatabaseConnection,不是定义它的文件路径);return_value=mock_conn 是关键——它让 DatabaseConnection() 调用返回你配好的 mock 实例。
用 mocker.patch.object 替换已有实例的上下文行为
当对象已在测试前创建好(比如 fixture 中初始化的 client),又需要临时让它支持 with,就得 patch 实例的特殊方法,而非类。
快速生成专业的 Python 脚本和应用代码。一键创建完整项目结构,支持CLI、API、爬虫、Bot、Django等多种项目类型,包含完整的项目结构、配置文件、依赖管理、测试、README和文档。
立即学习“Python免费学习笔记(深入)”;
mocker.patch.object(obj, '__enter__', return_value=obj)mocker.patch.object(obj, '__exit__', return_value=False)- 顺序不重要,但两个方法都得 patch,缺一不可
- 如果
__enter__需抛异常(模拟初始化失败),可用side_effect:__enter__.side_effect = ConnectionError
pytest-mock 不自动处理上下文,别指望 mocker.mock 返回的对象开箱即用
pytest-mock 提供的 mocker fixture 本质是 unittest.mock 的封装,它不会自动给 mock 对象加上上下文协议。所有上下文相关行为都要你亲手配置。
容易忽略的点:如果上下文体里调用了 mock 对象的方法(比如 db.query(...)),记得在 __enter__ 返回的对象上也提前设好这些方法的返回值或行为——否则会得到 Mock 默认返回的另一个 Mock,可能掩盖真实逻辑错误。

















