pytest 9.0.0 把 unittest.SkipTest 算成失败,升级后要检查跳过结果
pytest 9.0.0 曾将 unittest.SkipTest 误判为失败。检查实际运行器,采用包含修复的版本,并核对测试报告中的跳过状态与原因。
pytest 9.0.0 把 unittest.SkipTest 算成失败,升级后要检查跳过结果
原来显示 skipped 的测试,升级到 pytest 9.0.0 后突然显示 FAILED,回溯最后只有 unittest.case.SkipTest。如果测试没有执行新的断言,而是在执行 raise unittest.SkipTest(...) 时失败,先核对 pytest 版本。9.0.0 曾出现这项回归,9.0.1 恢复了对该异常的跳过处理。
它会影响直接抛出异常的普通测试函数,也影响 unittest.TestCase 的类初始化和跳过装饰器。在 Linux、Python 3.13.5 的对照环境中,同一个函数在 pytest 8.4.2 下跳过,在 9.0.0 下失败。因此,不能只看测试业务逻辑有没有变;运行器升级也可能改变结果分类。
可以先在项目当前虚拟环境执行:
python -m pytest --version
python -m pip show pytest
用 python -m pytest 能把测试命令绑定到当前解释器,避免 shell 中另一个 pytest 可执行文件造成版本误判。若项目用 uv、Poetry 或 tox 管理环境,应在实际运行测试的环境内检查,而不是查看系统 Python 安装的版本。
保存下面的文件为 test_skip_probe.py:
import unittest
def test_skip_probe():
raise unittest.SkipTest("当前环境不具备测试条件")
运行 python -m pytest -q -rs test_skip_probe.py。受影响版本会把它记为失败;恢复正常后应显示一项跳过,并输出原因。这个小案例适合判断是否命中本次回归,不能代替整个测试套件的验证。
保留原来的跳过语义
如果项目需要同时支持 unittest 和 pytest,优先调整运行器依赖,保留 unittest.SkipTest。首次包含修复的版本是 9.0.1;可以先在临时环境验证该版本,再按项目约束选用兼容的后续版本:
python -m pip install "pytest==9.0.1"
python -m pytest -q -rs test_skip_probe.py
python -m pytest -ra
最后一条用于跑项目测试并列出跳过等结果。确认原来的跳过数量和原因恢复后,再更新依赖声明及锁文件。只修改本地环境而不改锁文件,下次 CI 重建时仍可能安装 9.0.0。
若项目专门使用 pytest,普通测试函数也可以改为:
import pytest
def test_skip_probe():
pytest.skip("当前环境不具备测试条件")
这是一种代码迁移选择。共享测试库如果依赖 SkipTest 子类,或还要由标准库 unittest 运行,不宜批量替换;先修运行器版本更容易保持行为一致。
这次回归与 pytest 移除 nose 支持时改变异常处理有关。异常确实被抛出了,但运行器没有再将它正确识别为跳过。不要用 try/except unittest.SkipTest: pass 消除红色结果,那会把“条件不满足,没有运行测试”变成“测试通过”。验证时除了看 CI 是否变绿,还要看报告中的 skipped 状态,避免掩盖没有执行的测试。
如果已经运行 9.0.1 或兼容后续版本仍然失败,应检查实际解释器、插件和回溯;不要把所有跳过异常都归到这项已修复回归。


