用 @pytest.mark.slow 标记测试为“慢”,需在 pytest.ini 或 pyproject.toml 中注册 marker;通过 pytest -m slow 运行或 pytest -m "not slow" 跳过,语义由开发者定义而非耗时自动判定。

pytest怎么标记一个测试为“慢”
用 @pytest.mark.slow 装饰器,这是最直接、最被 pytest 原生支持的方式。它不依赖插件,也不需要改配置就能生效,但前提是你的项目里没禁用自定义 marker。
常见错误现象:加了 @pytest.mark.slow 却发现 pytest -m slow 没反应——大概率是 pytest 报告 “unknown marker”,说明你没在 pytest.ini 或 pyproject.toml 里注册它。
- 在
pytest.ini中加:[tool:pytest] markers = slow: marks tests as slow (deselect with '-m "not slow"') - 如果用
pyproject.toml,写成:[tool.pytest.ini_options] markers = ["slow: marks tests as slow (deselect with '-m \"not slow\"')"]
- 标记单个测试函数:
@pytest.mark.slow放在def test_xxx():上方 - 标记整个类:
@pytest.mark.slow放在class TestLongRun:上方,类内所有方法自动继承
如何只跑慢测试或跳过慢测试
核心靠 -m 表达式筛选,不是靠开关或环境变量。它的行为是“选中”,不是“启用”,所以逻辑要反着想。
使用场景:CI 流水线里拆分任务,本地开发时快速验证主干逻辑,或者夜间定时全量跑一次慢用例。
立即学习“Python免费学习笔记(深入)”;
安全 Python 代码沙箱:在隔离的沙箱中执行任意 Python 代码,预装 requests、NumPy、pandas 库。返回 stdout、stderr。
- 只运行慢测试:
pytest -m slow - 跳过慢测试(日常开发推荐):
pytest -m "not slow" - 同时匹配多个标签:
pytest -m "slow and integration",前提是你也定义并用了integrationmarker - 注意:如果命令行没加
-m,所有测试照常执行,@pytest.mark.slow不会自动禁用任何用例
为什么不能只靠 time.sleep() 判断是否“慢”
因为耗时不可控:同一段测试在 CI 机器、M1 Mac、Windows WSL 下跑出的耗时可能差 3 倍;而且 setup/teardown、fixture 加载、网络抖动都会干扰测量。靠硬编码时间阈值做自动分类,维护成本高、误报多。
真正该做的,是把“慢”的语义交给开发者判断——比如涉及数据库迁移、外部 API 调用、大文件生成、真实浏览器启动的测试,人眼就知道不该进 PR 检查流。
- 别写这种逻辑:
if time.time() - start > 5: pytest.mark.slow—— pytest 不支持运行时动态打标 - 别依赖
--durations=0输出后人工筛选——无法用于自动化调度 - 性能影响:标记本身零开销;但如果你在 fixture 里偷偷做了耗时操作再打标,那就本末倒置了
CI 中如何安全隔离慢测试
关键不是“怎么跑”,而是“谁来跑、什么时候跑”。直接在主 CI job 里加 -m "not slow" 最省事,但容易漏掉标记遗漏的用例;更稳的做法是显式拆成两个 job:一个 fast-only,一个 slow-only。
容易踩的坑:在 slow job 里忘了加超时限制,导致某个测试卡死拖垮整条流水线。
- GitHub Actions 示例片段:
slow-tests: runs-on: ubuntu-latest timeout-minutes: 30 steps: - run: pytest -m slow --tb=short - GitLab CI 同理,用
timeout:字段约束 job 总时长,比在 pytest 里设--timeout更可靠 - 不要在
conftest.py里全局pytest_runtest_makereport拦截慢测试——这属于过度设计,且和-m机制冲突
复杂点在于:有些测试“慢”是条件性的,比如只在特定 ENV=prod 下才触发重试逻辑。这种得靠参数化 + 组合 marker,而不是指望 pytest 自动识别。

















