> 测不出失败的门禁比没有门禁更糟——它在制造信心
一个浏览器扩展要把值写进表单。它的 benchmark 跑在保存下来的静态 fixture 上, 报表里有一列叫 filled。
// TABLE_OF_CONTENTS
结论先行¶
一个浏览器扩展要把值写进表单。它的 benchmark 跑在保存下来的静态 fixture 上,
报表里有一列叫 filled。
问题是:保存下来的 DOM 是死的,页面的 React 从来不会运行。 而 driver 存在的全部理由,恰恰是"框架会不会把这个值留下来"。 所以 driver 在 fixture 上"成功",对它真正要解决的问题一个字都没说。
一个在它声称要测的那件事上永远不会失败的门禁,比没有门禁更糟:它在制造信心。
修法不是让 fixture 更真,是把两件事拆开,各自对自己的范围诚实:
- benchmark 只给计划打分(选了哪个字段、填什么值),headline 指标改名叫 wrong-plan rate;
- driver 的正确性用 Playwright 单独验,打在一个专门造的真实 widget 页面上。
为什么¶
这个错误有个很稳定的形状:度量对象和被度量对象之间差了一层,而那一层正是风险所在。
- 在死 DOM 上测"写入成功" → 真正会出错的是框架的受控组件,而它没跑。
- 在
\input的外壳文件上跑查重 → 真正的正文在被 include 的文件里。 - 在打包器的输出目录上跑 lint → 真正发出去的是另一个目录。
- warmup 用短 prompt 跑通就报 ready → 真实负载里一半请求超窗。
它们共同的症状是绿色。不是误报,不是噪声——是一个干净的通过, 而它对应的现实从未被触碰。所以这类问题不会出现在失败列表里, 只会出现在"我们明明有测试"的事后讨论里。
第二条:发明出来的阈值不能当门禁¶
同一份决策记录里还有一条配套的:只有 wrong-plan rate = 0 从第一天起就是硬门禁, 其余指标(分类准确率、召回、延迟)先当目标,等真实基线测出来之后, 再按「基线 − 2 个点」变成门禁。
理由很直接:那些阈值是在任何测量存在之前拍的。 一个拍出来的门禁要么永远不触发(无用),要么挡住每一次提交(比无用更糟)。
而 wrong-plan = 0 在类别上不同——它是正确性不变量,不是性能百分比。 不变量从第一个 fixture 起就可执行,百分比必须等基线。
判据:这个门禁卡的是"不允许发生的事",还是"希望达到的水平"? 前者可以立刻设成硬门禁;后者在测出基线之前只能是目标。
怎么用¶
给任何 CI 门禁做体检,两个问题:
- 它能失败吗? 具体做法:故意引入一个它声称要抓的缺陷,看它红不红。 不红就说明度量对象和被度量对象之间有一层没对上。 这件事要在加门禁的当天做,不是等出事之后。
- 这个阈值是测出来的还是拍出来的? 拍出来的先写成目标,并在同一处写清楚"等 M4 的基线出来后转成门禁"。 没有这句话,它要么被忽略,要么被绕过。
还有一条命名上的小事但很有用:把指标名字改成它实际测的东西。
filled → wrong-plan rate。改完之后,"这个数在 fixture 上有意义吗"
这个问题自己就有答案了,不用靠读文档的人警觉。
出处¶
自己的一个自动填表浏览器扩展(私有未发布)的设计决策记录: 一条是"benchmark 给计划打分而不是给写入打分",一条是 "只有正确性不变量从第一天起是硬门禁,性能指标等基线"。 相关:没人过得去的闸门会被手动放行,而放行一次它就不再是闸门(门禁太严会被手动放行,是本条的反面)、 手写的自检清单永远是全绿的——它只包含你刚修过的东西、用 any() 写的回归测试是假保证——它只要求最容易过的那个夹具通过。