yield fixture在pytest中通过@pytest.fixture装饰函数,yield前为setup(可返回值),yield后为teardown(必执行);必须用yield而非return,否则teardown不触发。

yield fixture 在 pytest 中怎么写
pytest 里用 yield 写 fixture,本质是把 setup 和 teardown 合在同一个函数里:执行到 yield 前是 setup 阶段,返回值给测试用;yield 之后的代码就是 teardown,无论测试是否失败都会运行。
常见错误是忘了加 yield,只写 return —— 这样 teardown 部分根本不会执行。
- 必须用
@pytest.fixture装饰,不能用普通函数 -
yield后可以接一个值(比如打开的文件对象),测试函数会收到它 -
yield后面的代码在测试退出后才跑,哪怕测试抛异常也会进 teardown
@pytest.fixture
def tmp_db():
db = create_test_db()
yield db # 测试拿到这个 db 实例
db.close() # 一定会执行
为什么 yield 比 setup_method 更可靠
类级别的 setup_method/teardown_method 在 pytest 里不被推荐,因为它们绕过了 fixture 的依赖管理和作用域控制。而 yield fixture 天然支持 scope="function"、"class"、"module" 等粒度,并且能被其他 fixture 正确依赖。
典型坑点:多个测试共用一个资源但没控制并发或状态污染。比如用 scope="module" 的 yield fixture 创建一次数据库连接,所有测试共享,但 teardown 只在模块结束时触发一次 —— 如果中间某个测试改了表结构,后续测试可能失败。
- scope 要按需选:
function最安全,module要确保资源可重入 - 不要在 yield 后面做“可能失败”的清理操作(比如删只读文件),否则会掩盖原始测试错误
- 若 teardown 抛异常,pytest 默认把它当 warning 打印,不中断测试流程
yield fixture 怎么传参和复用
fixture 本身不支持直接传参,但可以用闭包或工厂函数包装。更常用的是用 params + request fixture 动态生成不同配置的 yield fixture。
Python 3.14.2是Python编程语言在2025年12月5日发布的稳定版本,属于3.14系列的第二个维护更新。该版本包含了18项修复,重点解决了多进程、数据类及正则表达式等模块的回归问题,并修复了CVE-2025-12084等安全漏洞。此版本标志着自由线程模式(移除GIL)正式获得官方支持,是Python发展的重要里程碑。
例如要测试多种数据库驱动,又不想写三个重复的 fixture:
@pytest.fixture(params=["sqlite", "postgresql"])
def db_engine(request):
engine = create_engine(request.param)
yield engine
engine.dispose()
测试函数里直接接收 db_engine,pytest 会自动跑两遍,分别注入不同实例。
- 避免在 yield fixture 内部做 heavy 初始化(如启动 Docker 容器),应移到 setup 阶段并加超时保护
- 如果需要跨 fixture 传递状态(比如 A 创建临时目录,B 往里写文件),用
tmp_path这类内置 fixture 更稳,别自己造 - yield 后的清理代码不能访问测试函数的局部变量,只能靠 fixture 自己维护上下文
清理失败时怎么调试
yield fixture 的 teardown 不报错,容易让人误以为“清理成功了”。实际中常见磁盘满、权限不足、进程残留导致 os.remove 或 shutil.rmtree 静默失败。
建议在 teardown 段加显式日志或断言:
yield temp_dir
if temp_dir.exists():
shutil.rmtree(temp_dir)
assert not temp_dir.exists(), f"Failed to clean {temp_dir}"
- pytest 默认不显示 teardown 日志,加
-s参数才能看到 print 输出 - 用
logging替代 print,配合--log-cli-level=INFO更易追踪 - 对关键资源(如端口、锁文件),teardown 后最好加一步验证,而不是只信“调用了 close()”
真正麻烦的不是写 yield,而是想清楚哪些状态必须清理、哪些可以交给 OS 回收。比如临时文件路径没用 tempfile.mkdtemp() 而是硬编码 /tmp/test_123,那 cleanup 就永远有竞态风险。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










