Deno 覆盖率把未走分支算已覆盖,关闭收集时的 V8 code cache
Deno run 命中 V8 code cache 后可能缺少块覆盖率计数,将未走分支标成已覆盖。已确认方案是测量时加 --no-code-cache,正式修复版本仍未知。
Deno 覆盖率第一次运行正确,第二次却把没走过的分支算成已覆盖,可以对照 V8 code cache 的冷、暖状态。这个问题在 deno run 收集覆盖率时出现,重新生成报告不能补回执行时缺失的计数。
// main.ts
if (Deno.args.length > 0) {
console.log('has args');
}
console.log('done');
不传参数时,has args 不应执行。Deno 2.9.6、macOS arm64 的案例中,空缓存第一次测量能识别该分支未覆盖;后续命中 code cache 后却显示全部覆盖。原材料也记录了 2.9.4 的同类表现。
V8 从缓存编译模块时没有生成相应的 block coverage counters,原始 profile 只剩顶层范围,isBlockCoverage 变为 false。报告于是把该范围内的行都当成被覆盖。应用分支没有改变,变化发生在编译与计数生成阶段。
已确认的操作方案是在每一个负责测量的 deno run 上显式关闭 code cache:
deno run --no-code-cache --coverage=cov-check main.ts
deno coverage --detailed cov-check
采用独立的新输出目录,保留此前的数据作为对照。也可以通过 DENO_COVERAGE_DIR 收集,但启动命令仍需要覆盖相同的 --no-code-cache 条件。此处不指定一个已经正式发行的修复版,不能仅因为主分支有补丁,就承诺升级某个包能解决。
deno test 自身不等于这条 deno run code cache 路径;然而测试启动的子进程可能继承 DENO_COVERAGE_DIR,又以 deno run 加载模块。应检查子进程实际参数,不能只给父测试命令加设置。关闭缓存可能增加启动开销,部署测量方案前应评估自己的测试规模。
验收至少比较无参数与有参数两条路径:前者的 has args 行应仍未覆盖,后者应覆盖。重复相同输入,让缓存原本会变暖的第二次测量也保持正确,并查看原始 profile 是否存在真正的块计数。
删除报告 HTML 再生成只消费旧测量结果,不会重新编译模块。也不要用排除注释隐藏未走分支。若冷、暖条件一致后仍有偏差,再调查源映射、数据合并或真实测试遗漏,不把所有覆盖率问题都归给 code cache。


