智汇 IT
城启新篇

单元测试覆盖率提升方法从被嫌弃的那行代码开始

去年冬天,园区楼下那家便利店早关门了,我们组的灯还亮着。一个同事把键盘往前一推,说了句:这覆盖率 91% 的项目,我改一行都手抖。

不奇怪。他管的是个对账服务,JaCoCo 报告绿得发光。可那 91% 里,一多半是 getter、setter 和构造函数。真正碰钱的判断藏在十几个 if 里,分支覆盖不到一半。

覆盖率高不等于安全网结实

先把概念对齐,不然后面全是各说各话。

行覆盖率:某行代码在测试里被执行过。听着挺实在,其实最容易注水。分支覆盖率:每个 if/else、三元表达式、switch 分支的两个方向都走到过。变异覆盖率:工具故意把代码改坏一处,看测试会不会报警。Java 用 PIT,前端用 Stryker,Go 那边也有类似方案。

这三个指标的狠劲是递增的。行覆盖最水,变异覆盖最凶。大部分团队的质量门禁只卡第一个,于是就有了 91% 的幻觉。

JaCoCo单元测试覆盖率报告分支覆盖率高亮标注截图
JaCoCo单元测试覆盖率报告分支覆盖率高亮标注截图

还有种更阴的:没有断言的测试。跑通了,不报错,但什么都没验证。它在报告里满分,在事故复盘会上是零分。

真正有效的做法其实都挺土的

我见过几个把覆盖率从 40% 拉到 75%、而且没把团队逼疯的小组,招数一点都不酷。

第一招,只卡增量。全量覆盖率设个底线别往下掉就行,重点卡在合并请求上:这次改动新增的代码,行覆盖和分支覆盖都要到 80%。老代码不追溯。为什么?因为让人去给三年前的屎山补测试,是性价比最低的活,谁干谁想跑。而新代码是热的,写测试顺手。

第二招,给难测的代码动手术。覆盖率上不去,八成不是测试写得差,是代码本身没法测。时间戳直接写在业务里,随机数直接调,HTTP 请求散在方法中间——这些东西让任何测试都变成玄学。把它们抽到边界外面,通过参数或者依赖注入传进来。改完之后你会发现覆盖率自己就涨了,跟测试写得好不好关系不大。

第三招,把报告塞进合并请求的评论区。别发周报。周报没人看。CI 跑完 JaCoCo,让机器人直接在 PR 下面贴一行:本次新增 37 行,覆盖 31 行,分支 4/7。人对着具体数字才有反应。

GitLab合并请求评论区自动化单元测试覆盖率增量检查机器人留言截图
GitLab合并请求评论区自动化单元测试覆盖率增量检查机器人留言截图

第四招,给排除清单一点诚实。生成的代码、纯 DTO、迁移脚本、main 函数,这些排除掉没人有意见。但你要是把 service 层也排除,那叫自欺欺人。这清单得有人 review。

说到底,覆盖率是个导向性指标,不是结果指标。它衡量的是你有没有为这段逻辑付出过思考,不是这段逻辑对不对。能替代它的只有变异测试,可惜跑得慢,一个中等项目跑一次半小时起步,多数团队只在核心模块上定期跑,当体检用。

几个我踩过的坑

几个我踩过的坑
几个我踩过的坑

坑一:为了数字补测试。我干过。给每个 getter 补一个断言,覆盖率一小时涨了八个点,然后被组长在 review 里骂了一顿。他骂得对。

坑二:门禁设成 100%。结果就是团队开始写 @Ignore,或者把断言删掉只留执行。指标是给人看的,人总有办法绕过去。

坑三:mock 满天飞。一个测试 mock 了六个依赖,最后测的是自己描述的那个假世界。这种测试在重构时会成批变红,然后成批被删,还不如没有。

坑四:把覆盖率挂到开发个人的绩效上。一旦和钱挂钩,数据立刻失去意义。信我。

如果你这周就想动手

如果你这周就想动手
如果你这周就想动手

不用开会,不用立项,做这几件事就行。

打开 CI,加一个增量覆盖率检查,阈值先定 70%,别太高。第二天看看数字,一般会吓一跳。
挑一个最常出 bug 的模块,写十个针对边界的测试,别碰正常路径,就盯着 null、空集合、超时、并发这几处。
把 new Date()、随机数、直接发 HTTP 的那几行揪出来,改成本地可注入的。
最后去报告配置里翻一遍,看看有没有夹带私货的排除规则。

做完这四件,覆盖率大概能从 50% 爬到 65%。剩下的那些是硬骨头,得靠时间和重构慢慢啃,急不来。

哦对,还有一件事。别指望覆盖率高就不出事故,它只是让你改代码的时候心里稍微踏实那么一点点。就这一点点,已经值回票价了。

免责声明:市场有风险,选择需谨慎!此文仅供参考,不作买卖依据。如有侵权请联系删除。
文章名称:单元测试覆盖率提升方法从被嫌弃的那行代码开始
文章链接:https://www.itcdj.com/news/852.html