coverage.py 的 --branch 参数必须显式开启,否则分支覆盖默认关闭;配置中 branch = true 必须小写,分支目标需用 --fail-under-branch(v6.4+)校验,且依赖 python 与 coverage 版本兼容。

coverage.py 的 --branch 参数必须显式开启
默认情况下,coverage.py 只统计行覆盖(line coverage),完全不看 if/else、for、三元表达式这些分支逻辑是否跑全。想测分支,必须加 --branch(或在配置里设 branch = true)。
常见错误是只跑 coverage run -m pytest,然后发现报告里 Branch 永远显示 “-”,不是 0%,而是“未启用”。这不是没跑够,是根本没开开关。
-
coverage run --branch -m pytest是最简启用方式 - 配置文件中要写成
[run]\nbranch = true,不能写branch = True或branch = on(ini 格式只认小写 true/false) - 如果用
pyproject.toml,对应字段是tool.coverage.run.branch = true
分支覆盖的“目标值”不是靠 coverage 命令直接指定的
coverage 本身没有 --min-branch 这种参数。所谓“设定目标”,其实是两步:先生成带分支数据的报告,再用 coverage report -m --fail-under=80 这类命令做阈值校验——但注意,--fail-under 默认只看行覆盖(total),不看分支(branch)。
真正控制分支覆盖目标的是 --fail-under-branch(v6.4+)或旧版的 --fail-under 配合 --skip-covered 等变通手段。
立即学习“Python免费学习笔记(深入)”;
- v6.4+ 推荐:
coverage report --fail-under-branch=85,失败时退出码非 0,CI 可直接中断 - 老版本只能靠脚本解析
coverage json输出,提取summary.branch_coverage字段比对 - HTML 报告里的百分比只是展示,不会自动触发失败;
--fail-under类参数只作用于终端 report 输出
哪些代码结构会被识别为“分支”?
coverage.py 的分支检测基于字节码,不是源码语法高亮。它只对明确产生跳转指令的结构建模,比如:
-
if/elif/else块(每个条件出口算一个分支) -
for/while的进入和跳出(空循环体也算分支点) - 布尔运算中的短路部分(
a and b中a为 False 时b不执行,这算一个未覆盖分支) - 不识别
try/except(异常路径不算分支覆盖范畴) - 函数定义、类定义、字符串拼接这些纯线性结构,永远不产生分支计数
所以别指望 coverage 能告诉你 except ValueError 有没有被触发——那是集成测试或 mock 的事,不是分支覆盖该管的。
容易被忽略的兼容性坑:Python 版本与 coverage 版本联动
分支覆盖在不同 Python 版本下行为不一致。比如 Python 3.12 引入了新字节码 POP_JUMP_IF_NONE,旧版 coverage(
- Python 3.11+ 建议用
coverage>=7.2,避免因字节码解析漏掉分支 - 使用
pyenv切换 Python 版本时,记得重装coverage,不要复用旧虚拟环境里的缓存 wheel -
coverage debug sys可查当前解析的字节码版本是否匹配运行时 Python 版本,输出里tracer行含PyTracer且无 warning 才算稳
分支覆盖不是开了 --branch 就万事大吉的事。它依赖底层字节码解释精度,而 Python 解释器自己还在变。每次升级 Python 或 coverage,都得重新跑一遍 coverage debug sys 和最小分支用例验证。










