我为什么把单元测试从“走过场”变成了“必修课”

举报
逆行时光 发表于 2026/10/23 08:13:55 2026/10/23
【摘要】 我为什么把单元测试从“走过场”变成了“必修课”说实话,我以前对单元测试的态度是:能跑就行,能不写就不写。理由很充分:需求天天变,写完就改,测了也白测;业务逻辑简单,肉眼 review 就够了;时间紧,写测试不如多写两个接口。这些话听着耳熟吧?我以前就是这么跟同事、跟自己说的。直到有一次,我改了一个“简单到不能再简单”的工具方法——把一个字符串截取函数从按字符数截取改成按字节数截取。改动不到...

我为什么把单元测试从“走过场”变成了“必修课”

说实话,我以前对单元测试的态度是:能跑就行,能不写就不写。

理由很充分:需求天天变,写完就改,测了也白测;业务逻辑简单,肉眼 review 就够了;时间紧,写测试不如多写两个接口。这些话听着耳熟吧?我以前就是这么跟同事、跟自己说的。

直到有一次,我改了一个“简单到不能再简单”的工具方法——把一个字符串截取函数从按字符数截取改成按字节数截取。改动不到 5 行,自测也没问题,就直接上了生产。结果第二天客服炸了:一批用户的昵称显示乱码,有的直接变成空字符串。原因很简单,我没考虑到 emoji 在 UTF-8 里占 4 个字节,按字节截取直接把 emoji 截断了。

如果当时我写了一个单元测试,覆盖一下 emoji、中文、中英文混排、边界长度这些 case,这个 Bug 根本走不出我的本地环境。但现实是,我花了整整一天处理客诉、修数据、发补丁。

那次之后,我强制自己给核心工具类和关键业务路径补单元测试。坚持了半年,发现单元测试给我的回报远不止“少出 Bug”这么简单。


一、测试是代码的“第一用户”

写测试的过程,其实是在从调用者的视角审视自己的代码。如果你发现一个方法很难写测试——要 mock 七八个依赖、要构造一堆复杂参数、要绕开各种静态方法——那大概率不是测试难写,是你的代码设计有问题。

我有一个工具类,最初写了十几个静态方法,互相调用,牵一发动全身。我想给其中某个方法写单元测试,结果发现得把整个类都 mock 进去。这逼着我做了一次重构:拆成两个职责单一的独立类,每个类只依赖自己需要的组件。重构完再写测试,每个方法两三行就搞定了。

测试倒逼出了更好的设计,这是我没想到的副作用。

二、测试是重构的“安全绳”

后来我们有一次大重构,要把一个跑了三年的老模块从单体里拆出去。如果没有单元测试,我根本不敢动——谁知道改完哪里会炸?但因为核心逻辑都有测试覆盖,我每改一步就跑一遍测试,看到绿色对勾就继续,看到红色就立刻修正。最终整个重构用了三天,零生产事故。

对比一下:之前另一个团队重构类似模块,没测试,上线后连出三天问题,最后不得不回滚。

三、测试文档化了“隐藏逻辑”

代码只告诉你怎么做,测试告诉你为什么这么做。比如下面这个测试:

@Test
void should_return_false_when_order_expired_and_already_paid() {
    Order order = new Order(PAID, LocalDateTime.now().minusDays(30));
    assertFalse(order.canRefund());
}

它不只验证了代码行为,还记录了业务规则:已支付且超过 30 天的订单不能退款。新人接手代码,看测试比看文档快得多。


一个务实的建议:不用追求 100% 覆盖率

很多团队把覆盖率当 KPI,要求 80%、90%,甚至 100%。我觉得没必要。我的策略是抓重点:

  • 工具类、算法、状态机、金额计算——这些必须测,出错了后果严重。
  • 纯 CRUD 的 Controller——测个参数校验和正常流程就行,不用每个分支都覆盖。
  • 外部调用、中间件交互——用集成测试覆盖,单元测试里 mock 掉。

与其追求数字好看,不如让每一行测试都真正保护一段关键逻辑。


现在我团队的规矩是:改老代码,先补测试;写新代码,测试跟代码一起提交。不要求完美,但要求你认真对待。因为单元测试不是写给领导看的,是写给那个未来凌晨三点被叫起来救火的自己看的。

如果你现在还在纠结“要不要写测试”,我的建议是:从明天开始,给下一个你写的工具方法加一个测试用例。就一个。写完你会发现,那种“有人替你把着关”的安全感,真香。

【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。