yield fixture 的 teardown 不执行,主要是因为 yield 后代码未被 pytest 捕获:yield 必须是函数最后一行可执行语句,且 fixture 需显式声明为参数,同名 fixture 需限定作用域,setup 异常或 yield 后清理异常未防护也会导致 teardown 失效。

yield fixture 的 teardown 不执行,绝大多数情况是因为 yield 后面的代码根本没被 pytest 捕获到——不是语法错,而是写法或调用方式破坏了 pytest 的执行链。
yield 必须是 fixture 函数里的最后一行可执行语句
pytest 依赖 yield 作为“分界点”来注入 teardown 逻辑。它会在 yield 执行后,把后续所有代码包裹进一个隐式的 finally 块里。但这个机制只在 yield 是函数体中**最后一个可执行动作**时才生效。
- yield 后面跟空行、注释、甚至一个未缩进的
pass,都会导致 pytest 忽略其后的所有代码 - 错误示例:
yield d; shutil.rmtree(d)—— 分号写在同一行也不行,pytest 解析器不识别这种写法 - 正确写法必须是:yield 单独一行,之后紧跟清理语句(且无任何干扰)
fixture 没被测试函数显式声明为参数
pytest 只对签名中明确列出的 fixture 名执行 setup/teardown 流程。autouse=True 会自动触发,但容易因作用域冲突失效;而没写参数名,就等于没调用。
- 写
def test_something():→temp_dirfixture 根本不运行,更别说 teardown - 必须写成
def test_something(temp_dir):,pytest 才会注入并保障 yield 后逻辑执行 - 同名 fixture 在多个
conftest.py中定义时,pytest 可能选错文件,建议加scope="function"显式限定
初始化阶段(yield 前)抛出异常或提前退出
yield 本身不会执行,如果 setup 部分失败,整个 fixture 就中断,teardown 自然跳过——这是合理行为,不是 bug。
立即学习“Python免费学习笔记(深入)”;
-
os.makedirs(path)权限不足 → 抛PermissionError→ yield 不执行 → teardown 不触发 - 误用
return或raise替代pytest.skip(),也会让 yield 被跳过 - 真正需要跳过时,应使用
pytest.skip("reason"),它允许 pytest 正常进入 teardown 阶段
清理逻辑本身被异常中断,且未做防护
yield 后的代码虽然“必执行”,但若其中某行抛出未捕获异常(比如 shutil.rmtree 遇到正在使用的文件),整个 teardown 流程会终止,后续语句不再运行。
- 错误写法:
yield d; shutil.rmtree(d)—— 若rmtree失败,后面再无机会执行其他清理 - 推荐写法:把清理包进
try/except,非关键失败就吞掉,避免阻断整个 teardown 链yield d<br>try:<br> shutil.rmtree(d)<br>except OSError:<br> pass
- 注意:不要在外层加
try/finally包裹 yield —— pytest 已内置该机制,手动加反而可能干扰
最常被忽略的一点:yield 后的代码是否真的“存在”——很多人复制粘贴时删掉了 yield 下方的行,只留个空行,然后反复检查逻辑却找不到问题。pytest 不报错,只是安静地跳过 teardown。


















