单元测试覆盖率提升方法的一线实操笔记

上周跟南京江北某互联网公司的后端组撸串,组长咬着烤串跟我吐槽,说上周上线的优惠券模块漏了个满减叠加的分支,用户凑单的时候多扣了三十多块,前后补退了快两千单,算下来光客服成本就小一万。

真的惨。

翻他们之前的迭代记录,三个月前就定了单元测试覆盖率要冲到60%的目标,最后停在41%再也没动过。那种明明打开覆盖率报告就能看到红块堆得像圣诞装饰,却总觉得业务迭代排期满、写测试是额外负担、等有空了再补的心态,我在至少七八个团队里见过。

别被虚高的覆盖率数字骗了

很多团队一提到提升覆盖率,第一反应就是把工具配好,跑个报告出来看数字。但我敢说,至少一半团队跑出来的覆盖率数字,根本没有参考价值。

JaCoCo配错路径,把测试代码本身算进覆盖范围,看着行覆盖率冲到了80%,实际业务代码才覆盖了30%。把第三方依赖的代码全排除在统计范围外,剩下的全是自己写的简单CRUD,数字好看得很,真出问题的时候全是没测到的核心逻辑。

更离谱的是那种为了凑数字,对着所有public方法挨个调用一遍,连个断言都不写的测试。跑通就算覆盖,分支走到就算达标,最后报告上红块全消,实际啥校验逻辑都没有。

纯纯自欺欺人。

Java电商订单模块JaCoCo覆盖率报告红块标注截图
Java电商订单模块JaCoCo覆盖率报告红块标注截图

之前有个做本地生活的团队,找我去看他们的覆盖率问题,说自己已经冲到85%了,线上还是经常出bug。我打开报告翻了十分钟,发现他们把所有ServiceImpl类的覆盖阈值设成了0,真正涉及商家结算金额计算的核心类,行覆盖率才22%,分支覆盖率更是低到11%。这种数字,要了有啥用?

别搞全员KPI摊派

很多团队为了快速提覆盖率,直接把指标拆到每个人头上,要求每个开发每周必须补够多少行测试代码,覆盖率涨多少。这种操作最后大概率会变成凑数字的闹剧。

说实话,项目里的代码根本不是一个权重。那些简单的Controller层,逻辑就是接个参数调一下service,返回个统一响应,这种代码哪怕你写100%的测试,对线上稳定性的提升也微乎其微。但那些涉及资金计算、规则匹配、用户权限校验的核心代码,哪怕你花一周时间把覆盖率拉到100%,能挡住的资损可能够给团队发半年奖金。

我之前接触过一个支付团队,一开始硬推全员写测试,两周下来覆盖率从34%涨到53%,但核心的对账模块覆盖率才27%,上线还是漏了个跨日对账的分支,导致财务对了三天账。后来他们直接调整了策略:非核心链路的代码,不设硬性覆盖率要求,只要不低于20%就行;涉及金额计算、数据同步的核心模块,覆盖率必须到90%以上,而且要求所有边界分支都必须有断言。就这一个调整,三个月下来,线上因为漏测分支导致的bug直接降了72%,大家也不觉得写测试是个负担了。

核心业务代码分支覆盖与行覆盖占比对比示意图
核心业务代码分支覆盖与行覆盖占比对比示意图

把写测试的成本打下来

大家抵触写测试,从来不是因为不想对自己的代码负责,是写测试的成本实在太高了。

你想啊,本来迭代排期就紧,写业务代码已经要熬到九点,写个测试还要自己new一堆实体对象,挨个set属性,mock七八个外部接口,写个测试花的时间比写业务代码还长,换谁谁都烦。

那把这些重复的活封装掉不就行了?

比如先搭个公共的测试数据工厂,不管是订单、用户还是商品,要造测试数据直接传参数生成,不用对着实体类的属性一个一个敲set。再把常用的mock逻辑做成自定义注解,只要在测试类上打个标记,框架自动把所有依赖的外部服务注入成符合预期的mock对象,根本不用写重复的when-then代码。

就这两个小改动,我之前帮团队搭的时候,写单个测试用例的平均耗时从12分钟降到了3分钟。效率上来了,谁还会觉得写测试是耽误迭代的额外工作?

对了,别总想着靠加班补测试。那都是治标不治本的。真的。

覆盖率从来不是用来给领导汇报的漂亮数字,是你写代码时,能帮你挡住藏在分支里的坑的手电筒。

数字好看没用。

能少出线上bug,才是真的有用。

免责声明:市场有风险,选择需谨慎!此文仅供参考,不作买卖依据。如有侵权请联系删除。
文章名称:单元测试覆盖率提升方法的一线实操笔记
文章链接:https://m.itcdj.com/it/153.html