本节摘要:pytest 的插件数以百计,全装上等于给自己埋雷。本节按"解决什么反馈问题"把生态分成五类:结构增强、度量、顺序与重复、并行提速、领域专用,给出每类的代表插件、启用时机与卸载信号。读完你应能为一支团队开出一份克制而够用的插件清单。
回顾测试框架的历史会发现一个拐点:xUnit 时代的扩展靠继承框架基类,门槛高、侵入强;pytest 把扩展点做成了插件协议——夹具、标记、钩子函数皆可插拔,于是生态爆炸。爆炸的另一面是选择困难,本节的任务就是把爆炸的生态折成一页决策表。
装插件的唯一正当理由是"它解决一个你已经拥有的反馈问题"。按问题归类:
| 反馈问题 | 代表插件 | 何时装 | 卸载信号 |
|---|---|---|---|
| 参数化与夹具不够用 | pytest-repeat、pytest-xdist(并行) | 用例上千、全跑过五分钟 | 用例回落、并行引发互踩 |
| 覆盖率看不见 | pytest-cov | 织网期找盲区、CI 门槛 | 只看数字不看盲区时 |
| 顺序随机化 | pytest-randomly | 抓隐藏的用例间依赖 | 依赖清干净后可退场 |
| 重复执行抓闪红 | pytest-repeat | 异步与时序用例体检 | 连续千次零闪红 |
| 异步与时间 | pytest-asyncio、freezegun | 第一条 async 用例出现即装 | ——常驻 |
| mock 手感 | pytest-mock | 第一处替身出现即装 | ——常驻 |
| BDD 故事层 | pytest-bdd | 业务方真读用例 | 特性文件无人看时 |
| Django/Flask 集成 | 对应官方插件 | 框架项目标配 | ——常驻 |
前两行值得注意的是"卸载信号"这一列:插件不是终身制。pytest-repeat 的使命是体检——把闪红抓干净之后,它就完成了历史任务;randomly 抓依赖同理。常驻的只有解决"结构性问题"的(异步、mock、框架集成),凡是为"阶段性问题"装的,问题解决就该考虑退场。
**一次只装一个,跑绿再装下一个。**两个插件在同一钩子上打架(比如并行与顺序随机的组合陷阱),是 CI 排障里最耗时的悬案;增量安装让每次红绿都能定位到具体插件。
**配置进版本库,不进口头传统。**pytest 的配置文件(pytest.ini 或 pyproject.toml 里的配置段)是团队契约:
[pytest] addopts = -q --strict-markers markers = e2e: 端到端旅程,合并前跑 slow: 超预算用例,夜间跑 testpaths = tests
--strict-markers 值得专门点名:没登记的标记直接报错,防止 @pytest.mark.e2e 打错字母后整批用例静默失踪。testpaths 把收集范围钉死,避免跑测试时误入构建目录的陈旧产物。
**每个插件都能说出它缩短了哪段反馈距离。**6.0 章节摘要立过标准:从改动到红灯的距离。并行把二十分钟压到五分钟,算;随机顺序把隐藏依赖提前三个月暴露,算;花哨的报告美化、截图生成器,说不清就算了——装得越多, CI 环境越脆、排障越难,克制的插件清单本身就是一种工程审美。选型还有条捷径可走:去同类成熟项目(语言生态里的头部开源库)看它们锁文件里的 pytest 插件名单——经过生产检验的最小集合,比榜单上的热门清单可信得多。
存量代码里常有一批 unittest 风格的老测试(继承 TestCase、self.assertEqual 家族)。好消息是 pytest 原生兼容它们——不改一行代码就能进 pytest 跑。迁移的正确节奏是"新债新规矩,旧债慢慢还":新测试一律 pytest 原生写法;老测试遇到要改的时候顺手转(assertEqual 改 assert,setUp 改夹具),不专门立专项。有个反向提醒值得记:pytest 里混用两种风格时,unittest 风格的用例享受不到夹具注入与原生断言的内省报告——这也是"顺手转"的价值所在,转一个,那个用例的失败信息立刻变友好。
配置文件(pytest.ini 或 pyproject 里的配置段)值得多花两行,因为它固化的是团队约定:
[pytest] addopts = -q --strict-markers --strict-config testpaths = tests markers = e2e: 端到端旅程,合并前跑 slow: 超预算用例,夜间跑 filterwarnings = error::DeprecationWarning log_cli = false
逐条说:--strict-config 让配置里的未知键报错,防止拼写错误静默失效;filterwarnings 把废弃警告升级为错误——依赖库的废弃通知从此在测试里就红给你看,而不是半年后在生产日志里见;log_cli 平时关掉,排障时命令行临时开。配置的哲学与插件清单一致:每行都要说得出"它防了什么事故",说不出的删掉,少即是快。
给刚起步的团队一份保底清单:pytest-mock(替身手感)、pytest-cov(盲区可见)、pytest-asyncio(遇 async 即装)、覆盖率门槛与标记注册进配置。四样以外的一切,等具体反馈问题出现再说。
⚠️ 插件清单膨胀的典型推手是"工具焦虑":看到别人家流水线有漂亮的趋势图就跟着装。先问自己的红灯在哪儿丢的——如果本地都没人跑测试,任何插件都救不了你;如果本地秒级反馈已经顺畅,多数插件你根本不需要。
💡 一条检验插件价值的方法:卸载它跑一周。团队毫无感觉的插件,本来就不该在清单上——生态的丰富是 pytest 的,反馈的顺畅是你的,别混淆这两个账户。
--strict-markers 守住标记注册,testpaths 钉住收集范围。