pytest内置神器全掌握:monkeypatch、tmp_path与capsys实用技巧清单
2026/9/17 22:35:16 网站建设 项目流程

pytest内置神器全掌握:monkeypatch、tmp_path与capsys实用技巧清单

【免费下载链接】pytestThe pytest framework makes it easy to write small tests, yet scales to support complex functional testing项目地址: https://gitcode.com/GitHub_Trending/py/pytest

pytest 是 Python 生态中最流行的测试框架之一,而它真正强大的地方,在于一套开箱即用的内置 fixture:monkeypatch让你安全地打补丁和修改环境变量,tmp_path为每个测试提供独立的临时目录,capsys则能精准捕获 print 输出的 stdout/stderr。本文为你整理这 3 个 pytest 内置工具的完整技巧清单——不安装任何插件,写代码时直接在测试函数参数里声明名字,即可自动注入、自动清理。

3大pytest内置fixture一页速览

在动手之前,先用一张表建立整体印象:

fixture注入方式核心能力自动清理
monkeypatchdef test_xxx(monkeypatch):替换属性/函数、改环境变量、切目录✅ 测试结束全部还原
tmp_pathdef test_xxx(tmp_path):每个测试独有的临时目录(Path 对象)✅ 默认保留最近 3 次运行
capsysdef test_xxx(capsys):读取测试中 print 到 stdout/stderr 的内容✅ 结束后恢复原始流

三者的共同哲学:测试中做的所有"破坏性"操作,都不应该泄漏到下一个测试。这正是 pytest 让新手写测试毫无心理负担的原因。

monkeypatch:如何安全打补丁而不污染环境

monkeypatch是 pytest 最常被用到的内置 fixture,它提供的是一组"改完必还原"的安全操作,源码位于 src/_pytest/monkeypatch.py。官方文档的完整示例在 doc/en/how-to/monkeypatch.rst。

一行代码替换函数(monkeypatch.setattr)

最常见的场景:被测代码依赖网络请求或用户目录,测试时希望它返回固定值。只需把函数替换掉,测试结束后 pytest 自动恢复原样:

def test_getssh(monkeypatch): monkeypatch.setattr(Path, "home", lambda: Path("/abc")) assert getssh() == Path("/abc/.ssh")

setattr的签名见 src/_pytest/monkeypatch.py,还支持直接传字符串目标(如"requests.sessions.Session.request"),无需 import 原模块。

设置环境变量、删除字典项、切换目录

常用方法作用源码位置
setenv/delenv安全增删环境变量monkeypatch.py#L334
setitem/delitem安全修改/删除字典项monkeypatch.py#L128
syspath_prepend临时修改sys.pathmonkeypatch.py#L363
chdir临时切换工作目录monkeypatch.py#L405

小技巧:删除可能不存在的东西时加raising=False,例如monkeypatch.delenv("USER", raising=False),避免"变量本来就不存在"时误报 KeyError。

monkeypatch 避坑三原则 ⚠️

  1. 别打补丁到内置函数(如opencompile),可能破坏 pytest 自身;
  2. 优先打"使用方"而非"源头":若你的模块写了from os import getcwd,应 patchmymodule.getcwd而不是os.getcwd
  3. 用 context 限定作用域with monkeypatch.context() as m:可以把补丁限制在代码块内,适合复杂 fixture(见 monkeypatch.py#L149)。

tmp_path:给每个测试一个独立临时目录

测试中要写文件?千万不要在源码目录里制造垃圾文件。tmp_path会自动提供一个pathlib.Path类型的临时目录,且每个测试函数都是全新的、互不干扰的。定义见 src/_pytest/tmpdir.py#L286。

def test_create_file(tmp_path): p = tmp_path / "hello.txt" p.write_text("content", encoding="utf-8") assert p.read_text(encoding="utf-8") == "content"

tmp_path 与 tmp_path_factory 怎么选

  • 单个测试用→ 直接用tmp_path,最简单;
  • 多个测试共享一份大文件(如生成的测试图片)→ 用会话级的 tmp_path_factory,配合@pytest.fixture(scope="session")只生成一次,避免重复计算。

临时目录在哪里?会留多久?

默认结构为{系统临时目录}/pytest-of-{用户}/pytest-{序号}/{测试名}/,pytest 会自动保留最近 3 次运行的目录,方便测试失败时回查现场。想自定义位置可用--basetemp参数,想调整保留策略可配置tmp_path_retention_count。详细规则见 doc/en/how-to/tmp_path.rst。

💡 排错神器:故意让最后一条断言失败,pytest 输出中会显示tmp_path = PosixPath('.../test_xxx0'),直接找到磁盘上的真实目录检查残留文件。

capsys:在测试中拦截 print 输出

想断言"某函数会打印特定内容"?用capsys就能在测试内部直接读取被捕获的输出,源码在 src/_pytest/capture.py#L1013。

def test_myoutput(capsys): print("hello") captured = capsys.readouterr() assert captured.out == "hello\n"

readouterr 的快照机制

readouterr()返回一个带outerr属性的命名元组,并且是快照式的:调用后缓冲区清空,之后打印的内容要再调一次才能读到——这让"先打印、再断言、再打印、再断言"的分步验证成为可能。

4个兄弟fixture,按需选择

fixture捕获层级返回类型适用场景
capsysPython 的sys.stdoutstr一般 print 断言(最常用)
capsysbinary同左bytes被测代码写二进制数据
capfd操作系统文件描述符 1/2str需要捕获 C 扩展、子进程输出
capfdbinary同左bytesfd 级 + 二进制

另外,测试中可以用with capsys.disabled():临时关闭捕获,让输出直接打到终端调试;命令行加-s则是全局关闭捕获。完整说明见 doc/en/how-to/capture-stdout-stderr.rst。

实用技巧清单:5条经验一次带走 ✅

  1. 参数声明即注入:三个 fixture 都不需要 import,测试函数签名里写上名字就能用;
  2. 共享逻辑抽 fixturemonkeypatch常与自定义@pytest.fixture组合,把"打补丁"封装成mock_response这样的语义化 fixture;
  3. 失败现场可回查tmp_path保留最近 3 次运行结果,断言失败时去磁盘看真实文件内容;
  4. 输出断言优先 capsys:比解析 JUnit 报告或用 print 肉眼检查精确得多;
  5. 临时文件用完就完monkeypatch的改动、capsys的流恢复都由 pytest 自动处理,测试函数里不用写一行还原代码。

延伸阅读:源码与官方文档入口

资料路径
monkeypatch 使用指南doc/en/how-to/monkeypatch.rst
tmp_path 使用指南doc/en/how-to/tmp_path.rst
stdout/stderr 捕获指南doc/en/how-to/capture-stdout-stderr.rst
全部 fixture API 参考doc/en/reference/fixtures.rst
monkeypatch 源码src/_pytest/monkeypatch.py
tmp_path 源码src/_pytest/tmpdir.py
capsys 捕获源码src/_pytest/capture.py

掌握monkeypatchtmp_pathcapsys这三个内置 fixture,你就拥有了 pytest 日常测试中最核心的"三件套":改环境、造数据、验输出,且全部自动善后——这就是 pytest "写小测试很简单,扩展也很强" 的最佳注脚。

【免费下载链接】pytestThe pytest framework makes it easy to write small tests, yet scales to support complex functional testing项目地址: https://gitcode.com/GitHub_Trending/py/pytest

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询