最常见原因是未指定--source参数,导致coverage只统计测试文件而漏掉src/等业务模块;必须显式设置coverage run --source=src/ -m pytest或在pyproject.toml中配置[tool.coverage.run] source = ["src"]。

coverage run 为什么没统计到你的模块
最常见原因是 coverage run 没指定源码路径,导致只记录了测试文件本身,漏掉被测模块。比如项目结构是 src/myapp/ 和 tests/,但直接运行 coverage run -m pytest,默认不会把 src/ 加入分析范围。
必须显式用 --source 或 --include 告诉它“哪些代码才算我的业务逻辑”:
coverage run --source=src/ -m pytestcoverage run --include="src/**/*.py" -m pytest- 若用
pyproject.toml配置,确保[tool.coverage.run]下有source = ["src"]
漏配 --source 的典型现象是:报告里只有 test_*.py 文件,myapp/*.py 根本不出现——这不是覆盖率低,是压根没被扫描。
pytest-cov 报告显示 100% 但实际有分支没跑
pytest-cov 默认只统计行覆盖(line coverage),对 if/else、try/except 这类分支逻辑完全不敏感。你看到的“100%”可能只是每行都执行过,但某个 else 分支一次都没进。
必须加 --cov-branch 开启分支覆盖统计:
coverage run --source=src/ --branch -m pytest-
coverage report -m输出里会多一列Branch,值为100%才真安全 - HTML 报告中未覆盖分支会标红,并在行尾显示
1->2这类跳转缺失提示
不加 --branch 就谈覆盖率,等于只查了“有没有人进门”,却没看“每个房间门是否都打开过”。
仅使用 Python 将 Claw Code 虚拟化框架与 OpenClaw 集成,提供 184 种工具和 200 多条命令,用于安全分析和代码质量...
参数化测试(parametrize)让覆盖率虚高
@pytest.mark.parametrize 如果写得粗糙,很容易造成“整行标绿,但分支没触发”。比如一个函数有 if x > 0: ... else: ...,但所有参数都是正数,else 分支就永远沉默。
真实提升需要两步动作:
- 先用
pytest --collect-only确认生成的用例数和你预期一致(避免因参数结构错误导致用例数量缩水) - 强制覆盖所有分支:给参数列表补上负数、零、None 等边界值,或用
ids显式标注意图,例如ids=["positive", "zero", "negative"] - 配合
--cov-branch,再跑一遍,看 HTML 报告里红色分支是否消失
别依赖“看起来参数很多”就以为覆盖全了——覆盖率工具不会猜你心里想测什么,它只认实际执行路径。
CI 中覆盖率掉线的隐藏原因
本地跑是 95%,CI 流水线里突然变成 70%,大概率不是代码问题,而是环境差异:
- Django 或 FastAPI 启动时自动 import 的模块,可能在
coverage run开始前就被加载了——这些模块的覆盖率永远为 0(coverage只能记录启动后执行的代码) - CI 使用了并行测试(如
pytest-xdist),但没配coverage combine,导致多个.coverage文件没合并,报告只取了其中一个 - 某些 CI 镜像预装了旧版
coverage(如 4.x),不支持--branch或对异步代码统计异常;应固定安装coverage[toml]>=7.0
真正可靠的 CI 覆盖率命令链是:coverage run --source=src/ --branch -m pytest -n auto → coverage combine → coverage report -m --fail-under=90。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










