智汇 IT
城启新篇

别把单元测试当额外KPI

上周帮前团队排查线上故障,一个支付优惠的计算逻辑改了个满减门槛,上线三小时超发十几万优惠券。

当时负责上线的开发盯着告警面板,手都在抖。

查了半天才发现,改逻辑的新人根本不知道之前的代码里藏了个隐藏判断:当订单实付金额低于门槛五毛的时候,会自动触发新人专属的额外折扣。这个逻辑没留任何文档,也没有任何测试覆盖,新人把判断条件删了之后,所有订单都能吃到这个折扣。

群里运营的消息刷了满屏,财务在电话里算损失的数字的时候,整个组的人都沉默了。

谁都知道为啥会出这事儿。之前大家一直把单元测试当排期里可砍的冗余项,觉得写业务代码就够了,测试是QA的事儿。

踩过的坑比写过的测试多

我之前在电商团队待过三年,见得太多了。

老员工离职留了个会员积分计算模块,没人接得住。新来的小伙子要改积分抵扣比例,改完上线直接清了一半用户的历史积分。原因是老代码里藏了个兜底逻辑:当用户积分余额为0的时候,会触发一次历史数据同步,把用户的历史积分从备份库拉回来。这个逻辑没有任何测试,也没人知道,小伙子改抵扣规则的时候,觉得这个判断是冗余代码,顺手就删了。

电商项目单元测试覆盖率报告截图
电商项目单元测试覆盖率报告截图

说真的,当时整个组通宵补数据的时候,没人好意思说“我早觉得应该写测试”。之前提过要给这个模块补测试,被组长以“排期太满”打回来了。

很多人对单元测试的误解太深了,总觉得这是给团队交差的任务,是给QA省事儿的工具。错了。单元测试的第一受益人永远是写这段代码的人自己,不是团队,不是QA,不是产品。你今天写的逻辑,三个月之后你自己都记不住当时为啥要写那个奇怪的if判断,更别说边界条件了。等你回头改的时候踩坑,花的时间可比当初写两个测试用例多十倍。

别追求100%覆盖率的假把式

当然,我也见过走另一个极端的团队。

上来就定KPI,要求单元测试覆盖率必须到80%以上,达不到就扣绩效。结果大家为了凑数,给所有的getter、setter写测试,给常量定义写测试,甚至给纯空的构造函数写测试。凑出来的覆盖率报表看着漂漂亮亮,真到核心逻辑的地方,测试用例一个没有。

凑数的单元测试无效用例代码片段
凑数的单元测试无效用例代码片段

之前见过一个同事写的测试用例,逻辑简单到离谱:new了个User对象,传了个名字参数,然后调用getName()方法,断言返回值和当初传的名字一样。这有啥用啊?完全是浪费时间。

说实话,我现在根本不看覆盖率数字。那些纯CRUD的接口,只是把数据库的内容读出来返回给前端,真的没必要写测试。写了之后,你改个字段名测试就挂,反而成了开发的负担,最后大家对单元测试的抵触情绪越来越大,干脆全删了图清净。

真正值得写测试的,是那些绕一点的核心逻辑。比如满减计算的临界值判断,积分抵扣的正负余额处理,第三方接口超时之后的重试逻辑,用户权限的边界校验。这些地方的测试写了,才是真的给自己留后路。

把测试写在代码提交之前

把测试写在代码提交之前
把测试写在代码提交之前

我现在带的小团队,根本不搞覆盖率考核,但是有个硬规矩:涉及金额计算、用户权限判断、核心数据同步的逻辑,提交代码合并请求的时候必须带上对应的单元测试,不然直接打回。

刚开始大家也嫌麻烦,说耽误写业务代码的速度。直到上个月改支付退款的逻辑,有个新人写的测试里发现了个问题:当用户提交的退款金额超过订单实付金额的时候,系统会直接生成负数的退款流水,相当于给用户多打钱。这个问题功能测试的用例里根本没覆盖——QA哪能想到有人会恶意提交超限额的退款申请啊。但是写单元测试的时候,你顺着逻辑想边界,自然会把这些极端场景试一遍。

当时发现这个问题的时候,整个组都松了口气。这要是上线了,被黑产刷几个小时,损失可比写那两个测试用例的时间多太多了。

别把单元测试当成项目的收尾工作,它应该是你写核心逻辑时的一部分,就像你写完代码要自己先跑一遍一样自然。很多人觉得写测试慢,其实算算账就知道了:你花5分钟写两个边界测试,比你上线之后出问题,花3小时排查、回滚、给用户发补偿、写事故报告,划算一百倍。

昨天和之前的老同事聊天,说他们现在终于把之前那些凑数的测试全清了,只留了核心逻辑的测试,大家写的时候也不抵触了,上个月的线上故障数比之前降了六成。

挺好的。

写代码哪有什么捷径啊。那些你当初偷的懒,迟早要在深夜的告警电话里还回来。

免责声明:市场有风险,选择需谨慎!此文仅供参考,不作买卖依据。如有侵权请联系删除。
文章名称:别把单元测试当额外KPI
文章链接:https://m.itcdj.com/news/726.html