跳转到内容

12. 故意改坏实现,看测试能否发现

约 30 分钟 难度:进阶 动手章

覆盖率统计的是有多少行代码在测试里被运行过。「被运行过」和「被检查过」是两回事:第 4 章那组回声测试把代码全跑了一遍,覆盖率好看,却什么都没验证。

这一章换一个更狠的问法:故意把实现改坏,测试抓得住吗?抓得住,说明断言真的在守这处行为;抓不住,说明这处行为没人看着。

拿第 7 章那份已经全绿的解析实现,逐个植入一处小改动,每次只改一处,改完就跑一遍测试,再改回来。改动都很小,像手滑写错:

被植入改动的这两行
const missingUnit = !unit;
const missingPrice = price === '' || price === undefined || Number(price) === 0;

计划植入四处:

  • 改动一(反转判断):!unit 改成 unit,让缺单位的逻辑反过来。
  • 改动二(改错常量):Number(price) === 0 改成 Number(price) === 999,让价格为 0 不再算缺失。
  • 改动三(删一条分支):删掉 || Number(price) === 0,价格为 0 的处理整个消失。
  • 改动四(去掉一步整理):把分隔后 .trim() 去掉,不再清理字段两端的空格。

每植入一处就跑一次 node --test,记录结果:

植入的改动测试结果说明
反转缺单位判断变红缺单位那条测试抓住了它,被「杀死」
价格判断改成 999变红价格为 0 那条测试抓住了它,被「杀死」
删掉价格为 0 分支变红同上,被「杀死」
去掉字段整理 .trim()仍全绿没有任何测试抓住它,「存活」

前三处一改就红,说明有断言在守着对应的行为。第四处改坏了,测试却一片绿,它「存活」了下来。存活不是好消息,它说明「字段两端有空格也要能正确解析」这件事,现在没有任何一条测试在检查。

存活的变异指向要补的验收条件

Section titled “存活的变异指向要补的验收条件”

每一处存活的变异,都是一条该补的验收条件。第四处存活的改动,对应的补强是:

字段两端有多余空格时,应当被清理后再解析。

把它写成测试:

parse-quotes.test.js
// 补强:字段两端的空格要被清理
test('字段带空格也能正确解析', () => {
const rows = parseQuotes(' M6 螺母 , 个 , 0.18 ');
assert.equal(rows[0].unit, '个');
});

加上这条测试后,再把 .trim() 去掉试一次,这一次测试会变红。原先存活的变异被杀死了,空白补上了。

每一处存活的变异记一行,连同它对应补强的验收条件,攒成一份清单。这份清单把「测试到底严不严」从一句感觉变成了一份具体的账:哪几种改坏能被抓住,哪几种漏了,漏的已经补了哪些。

第三幕到这里收束。判断的依据一路从「AI 说已经完成」,转到了可审查的改动、真实使用者的反应,和这一章的反事实检查。手里的工具不只是能跑,还经得起有人故意找茬。

这一节有错或讲不清? 提个 Issue 直接改文档 请作者催更