单元测试到底在测什么

举报
茉莉风铃 发表于 2026/10/04 11:08:46 2026/10/04
【摘要】 区分值得测的分支边界和凑数的覆盖率代码,讲测行为而非测实现、覆盖率该怎么用,并给出一条务实的落地顺序。

一、争议在于大家测的东西不一样

有人写测试是为了验证逻辑正确,有人是为了重构时不回归,有人是为了写文档。目的不同,测法的差别很大,吵起来谁也没错。

我自己的判断是:单元测试最值钱的产出不是"它跑了多少个用例",而是"以后改这块代码我敢不敢动"。

二、真正该测的和经常被测错的

该测的:分支和边界。

// 值得测:三种输入走向三条不同路径
function level(score) {
  if (score >= 90) return 'A';
  if (score >= 60) return 'B';
  return 'C';
}
level(95); // 'A'
level(60); // 'B'  ← 边界值,最容易漏
level(59); // 'C'

不值得单独测的:getter/setter 和拼装代码。

// 这种测试没有任何价值,get 天然返回 set 进去的值
expect(user.getName()).toBe('张三');

它测的是语言本身,不测业务。写它只是为了让覆盖率数字好看。

三、测代码而不是测实现

这是最关键的一条,也是重构最常踩的坑。

// 测实现细节:改内部结构就全红,业务其实没变
expect(calc.compute()).toBe(30);

// 测行为:只要对外表现不变,改内部怎么改都安全
expect(calc.add(10, 20)).toBe(30);

前一种测法下,代码里换一种方式求和,测试就挂了,但功能完全正常。团队会开始觉得测试是负担,然后有人去改测试迁就代码,最后测试就彻底失守了。

判断标准很简单:你的测试在代码重构时会红吗? 会,说明测到实现细节了。

四、覆盖率这个数字的正确用法

它是找盲区的工具,不是质量指标。

  • 某个文件覆盖率 0%:这块完全没被测过,看看是不是重要逻辑。
  • 某个分支覆盖率低:有一半情况没被覆盖,通常就是边界条件。
  • 某行覆盖了但断言很弱:比如只断言"不抛异常",等于没测。

反过来,追求整体覆盖率到 90% 往往会写出一堆凑数的测试。数字达标了,重构时照样不敢动。

五、一个务实的做法

一、先给核心的纯函数写测试。 输入输出明确、没有副作用的函数,测起来最省力,收益最高。

二、涉及数据库和网络的不写单元测试,写集成测试。 硬把数据库 mock 掉测出来的通过率没有意义,因为你 mock 的那层正是最常出问题的地方。

三、测试名写清楚意图。 测试折扣计算 不如 满200减30时返回170。失败时从测试名就能看出哪个行为坏了。

四、让失败信息可读。 断言里带上实际值,排查时不用重跑一遍。

六、最后说句实话

单元测试有成本,尤其是逻辑简单的项目——花三倍时间测一个只有三行的函数,性价比不高。这种情况不如把精力放在手工验证上。

但一旦代码涉及金额、权限、状态流转、多端一致性,测试的性价比会陡增,因为这些东西错一次的代价远大于写测试的时间。这是我实际的判断线:按后果的严重程度决定要不要测,不按覆盖率决定。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

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

全部回复

上滑加载中

设置昵称

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

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

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