外观
我对测试的态度转变
约 1304 字
我对测试的态度转变
我对测试的态度,三个阶段:
① 新人期:「测试是 KPI 负担,能跑就行」
② 受伤期:「没测试的代码,改一次炸一次」
③ 现在:「测试是杠杆 —— 花在刀刃上时最值」这篇讲这个转变,以及现在的「实用测试观」: 不追覆盖率数字,只求该有的地方有。
一、受伤期的那次
第二个项目,我接了个「就改个小地方」的需求: 订单状态流转,加一个「已退款」状态。
当时没测试。改完,自测通过,上线。 三天后客服炸了:部分老订单走到「已发货」分支时, 状态判断漏了新状态,直接抛异常 —— 用户订单卡死。
根因:我改 switch 时以为「就加个 case」, 不知道另一个模块也用同一套状态判断(全局搜漏了)。
那晚修到凌晨。如果有测试覆盖那条链路, CI 就拦住了,不用劳动用户和客服。
二、转变:测试是「改代码的许可证」
没测试的代码,你敢改吗?
改之前:反复读相关代码,自测半小时,上线后盯着监控
改之后:跑一遍测试(绿的),合测试给的是「放心重构」的权利。 没有它,每次改动都是赌博 —— 项目越大, 赌注越大。这就是「遗留系统没人敢动」的成因: 不是代码烂,是没有安全网。
(重构笔记 里 Fowler 说「先有测试再重构」,当年觉得教条,那次之后 奉为真理。)
三、实用主义测试观
不追覆盖率
覆盖率 80% 的团队,代码质量不一定好; 30% 的,也可能很稳。数字是手段不是目的。
我信的标准:
核心链路必须有测试(下单、支付、登录 —— 错了就是事故)
边界条件值得测(空、超长、并发、异常输入)
容易回归的多测(改过 bug 的地方,补测试防再犯)测试金字塔(简化版)
单元测试(多):纯函数、工具方法 —— 快、稳、好写
集成测试(中):模块协作、接口 + 数据库 —— 抓真问题
E2E(少):关键用户路径(登录→下单→支付)—— 保命新人常见错:一头扎进单元测试,把 getter/setter 测了个遍(没用),核心链路裸奔(可怕)。
写「能失败的测试」
// ❌ 永远绿的测试(没断言 = 没测)
test('计算金额', () => {
calculate(100)
})
// ✅ 会失败的测试(断言具体值)
test('计算金额', () => {
expect(calculate(100)).toBe(80)
})review 测试代码时,我的第一个问题永远是: 「这个测试,如果代码写错了,它会红吗?」 —— 答不上来的,删掉重写。
四、TDD:用但不是教条
TDD(先写测试再写代码)的实际情况:
适合:
- 需求明确的小功能(工具函数、算法)
- 修 bug(先写复现 bug 的测试,红了再修 ——
「回归测试」的标准姿势)
不适合:
- 探索期(接口都没定,写什么测试)
- UI 探索(先看到再测)
- spike 代码(验证可行性的一次性代码)我的用法:核心逻辑 TDD,探索代码先跑后补, 修 bug 必须「先写复现测试」。 最后一招是精华 —— 它保证「这个 bug 永远不再犯」。
五、工具链(前端向)
Vitest —— Vite 项目首选,快,API 像 Jest
Jest —— 老牌,生态全,配置略重
Testing Library —— React/Vue 组件测试标准(测行为不测实现)
Playwright —— E2E,多浏览器,比 Cypress 轻
Supertest —— Node 接口测试本站(VuePress)没写测试 —— 老实说:内容站, 「测试」的边际价值低(构建过了就是绿的)。 这就是「实用主义」:不是什么都配拥有测试。
六、什么时候可以没有测试
诚实清单:
- 一次性脚本:跑完就扔(数据分析、迁移脚本);
- 原型/验证代码:证明了想法就重写;
- 纯静态内容:本站这类(构建 + 人工预览就是测试);
- 团队没人会维护:写了也没人跑,不如不写。
但「核心业务逻辑」永远不在此列。 分界线: 错了会死人(事故/丢数据/资金)的地方,必须有; 错了也就错了的地方,可以不写。
七、给「测试无用论」的一句话
说「测试拖慢进度」的,算的是这个 sprint 的账。
把时间拉到一年:没有测试的系统, 每次改动多花三倍时间自测,加上事故修复、 半夜 oncall、不敢重构的技术债利息 —— 这笔账,只是没人记在 KPI 里。
测试不是成本,是把「未来的自己」从加班里 赎出来的保险。
小结
测试观三句话:测试是改代码的安全网、 覆盖率是数字不是目标、核心链路必须有而玩具不必。 从「测试是负担」到「测试是杠杆」的转变, 始于一次凌晨的事故。希望你不用交这个学费 —— 但如果你正在交,记住:这次学费, 买的是「下次敢改」的胆。