把清理代码写在yield之后,并不代表夹具准备阶段无论在哪里失败都会执行它。pytest的官方夹具指南明确说明:如果一个yield夹具在到达yield之前抛出异常,pytest不会尝试执行这个夹具在yield后面的清理代码。[1]
这与正常运行顺序有关。指南说明,pytest先确定夹具的线性顺序,依次运行到返回或yield,再继续下一个。测试结束后,pytest沿相反顺序处理已经yield的夹具,运行其后面的代码。到达yield既把准备结果交出去,也标出了这段后续清理所属的夹具。
失败的范围需要保留原文的另一半:对于此前已经成功运行的其他夹具,pytest仍会尝试按正常方式清理。因此,“夹具乙在yield前报错”不能简写成“整个测试的清理全部失效”。不同夹具走到了不同阶段,就需要分别说明它们的状态。
设想本文构造的依赖情境:夹具甲已完成准备并到达yield,夹具乙随后准备另一项资源,却在自己的yield之前出错。依据上述规则,乙的后半段清理不会被尝试,甲的清理仍会被尝试。这里强调的是尝试执行,不保证清理自身不会再报错;本文也没有运行这个例子或创建真实资源。
指南的Safe teardowns段落展示了把多项准备动作放在同一夹具中的问题:若其中一步在yield前失败,后面的整段清理便没有执行机会。它接着讨论将单项状态改变与对应清理组合到独立夹具中的结构。这个说明帮助理解失败边界,不是对未知项目作出“拆分后必无残留”的保证。
直接注册finalizer又有不同条件。原文提醒,清理函数一旦通过addfinalizer登记,即使该夹具随后抛出异常,pytest也会运行它。因此,注册时点与实际完成了什么动作有关,不能只把yield换成另一种写法,就认定所有清理问题已经解决。本文没有提供外部服务的删除或恢复步骤。
本文于2026年10月10日读取pytest stable文档中yield夹具、异常处理及安全清理相关段落,未从示例输出推定当前安装版本,也未把文档的通过输出记为本项目测试。分析准备阶段的失败时,可以先标明哪个夹具到达了yield、哪个尚未到达,再结合真实日志核对清理尝试;这样比一句“清理没执行”更能保留问题发生的位置。
信息来源
本文基于上述公开资料整理,未使用来源页面的图片、视频或嵌入媒体。