pytest --fixtures 遇到收集错误仍返回 0,CI 要单独检查收集
pytest 的 fixture 展示入口可能丢掉失败状态。把 collect-only 与列表生成分开,保留 CI 的真实退出状态;收集通过也不能代替测试执行。
CI 用 pytest --fixtures 生成 fixture 列表,日志已经出现收集错误,进程却返回 0,后续步骤照常发布报告。不要把这个命令的成功状态当成“测试项目能正常收集”。
pytest 9.1.1 的正式实现里,--fixtures 和 --fixtures-per-test 有专用入口:调用展示函数后直接返回 0。展示函数内部虽会进行收集,但错误状态未必像正常测试入口那样传播。这条路径也在后续 9.2.0 开发构建中出现过,不能把开发版号写成已经正式发行的版本。
展示列表与验证收集分成两个步骤
需要验证收集是否可用时,在原来获准运行测试的开发或 CI 环境中,先单独执行:
python -m pytest tests/ --collect-only
tests/ 换成项目真实的测试入口,并保留原有配置、插件、必要参数和工作目录。收集会导入 conftest、插件与测试模块,可能执行它们的初始化代码;它不是只读取文件名的无副作用扫描。
让 CI 直接采用这个步骤的真实退出状态。只有收集验证通过,再生成 fixture 文档。例如已经使用 shell 顺序任务时,可以这样表达前后依赖:
python -m pytest tests/ --collect-only && python -m pytest tests/ --fixtures
不要在后面无条件接 echo,再把最后一条命令的状态当成 pytest 的状态。需要把输出交给 tee 或其他程序时,也要按当前 shell 和 CI 执行器的规则保留 pytest 的失败状态,不能只检查管道最后一个进程。
收集通过仍不等于测试执行通过
--collect-only 不执行正常的测试函数和 fixture 生命周期。缺少数据库、fixture setup 失败或断言失败,仍可能要到正式测试步骤才暴露。它只适合作为“项目能否收集”的门槛;如果后续流程依赖测试通过,还必须保留原有测试步骤。
fixture 列表本身也可能不完整:收集中途失败时,输出只包含已经发现的内容。不能在退出状态为 0 后直接覆盖上一份有效文档,应把收集验证结果与生成产物分别判断。
截至 2026 年 10 月 24 日,正式 9.1.1 仍能核到上述固定返回值,不能把计划中的 pytest 10 行为或提交的补丁当作已发行修复。后续升级应核对具体正式版本,并在隔离项目中覆盖成功收集、受控收集失败和内部错误等实际依赖的分支。
修订 CI 后,确认失败会阻止依赖它的下一步,且正常分支仍生成预期 fixture 列表。原收集错误仍需要按日志修复;多加一道正确的退出状态检查,不会自动解决缺包、参数错误或测试模块导入失败。


