最小可行配置需显式创建并激活虚拟环境、隔离安装依赖、指定测试路径与覆盖率输出格式、启用缓存及完整traceback,确保pytest在CI中稳定执行。

直接上手就能跑通的最小可行配置,核心是让 pytest 在 CI 环境里稳定执行,而不是卡在依赖、路径或环境变量上。
test 阶段必须显式激活虚拟环境
GitLab Runner 默认不带激活的 Python 环境,即使指定了 image: python:3.9-slim,pytest 仍可能因未隔离而与系统包冲突。不建虚拟环境,容易出现 ImportError 或版本错乱(比如本地装了 pytest==9.0.2,CI 里却用上了旧版)。
实操建议:
- 在
before_script中固定创建并激活:python -m venv venv && source venv/bin/activate - 安装依赖必须走这个环境:
pip install -r requirements.txt && pip install pytest pytest-cov - 避免用
pip install --user—— CI Runner 通常没写权限,会静默失败
pytest 参数要适配 CI 输出格式
本地跑 pytest 看着正常,但 CI 日志里测试通过数为 0、或报 No tests were found,大概率是路径或参数没对齐。GitLab CI 的工作目录默认是项目根,但 pytest 不会自动递归扫描 tests/ 下所有文件,尤其当测试模块有 __init__.py 缺失或命名不规范时。
立即学习“Python免费学习笔记(深入)”;
实操建议:
- 显式指定测试目录:
pytest tests/ --cov=src/ --cov-report=term-missing(假设源码在src/) - 加
-v查看实际加载了哪些测试用例,避免漏掉test_*.py以外的命名风格 - CI 中禁用
--tb=short以外的 traceback 格式,长堆栈会刷屏、掩盖关键错误
缓存 .cache/pip 和 venv/ 能省掉 40%+ 时间
每次 job 都重装全部依赖,不仅慢(尤其含 numpy、torch 类包),还容易触发 PyPI 限流导致 ConnectionError。GitLab 的 cache 机制能复用 pip 下载包和已编译的 wheel,但配置不当反而失效。
实操建议:
- 在 job 级别声明缓存路径:
cache: paths: [".cache/pip", "venv/"] - 加上
key: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG",避免 test 和 deploy 共享同一份缓存引发冲突 - 不要缓存
site-packages整个目录 —— 它随 Python minor 版本变化,缓存后可能在python:3.9和python:3.10间出错
测试失败时别只看最后一行红字
CI 流水线里 pytest 报错常被截断,比如只显示 TypeError: expected str, bytes or os.PathLike object,但没说哪行代码、哪个 fixture 出问题。根本原因是 CI 默认不保留完整日志缓冲区,且 pytest 的详细输出被压缩了。
实操建议:
- 强制输出完整 traceback:
pytest tests/ -v --tb=long - 把覆盖率报告导出为 XML,供 GitLab 原生解析:
--cov-report=xml,再在.gitlab-ci.yml里加coverage: '/^TOTAL.*\s+([0-9]{1,3})%$/' - 遇到超时类失败(如 HTTP 请求卡住),加
--timeout=30(需装pytest-timeout),防止 job 挂死占满 Runner
最常被忽略的一点:GitLab CI 的 test job 默认不继承 before_script 的环境变量,如果测试里用了 os.getenv("TEST_DB_URL"),得在 job 内显式定义 variables: 或用 export 设置,否则就是空字符串——连报错都不会有,只会静默连接失败。


















