测试应该聪明,而不是教条的 | AI生成和翻译

Home 2026.03

问题:https://www.yinwang.org/posts/tests 这篇文章说了什么?

回答:

这篇文章标题为 “On Tests”,作者是 王垠(Yin Wang),一位以软件工程强硬观点著称的中国计算机科学家。本文反对 test dogmatism —— 盲目过度依赖软件测试作为代码质量衡量标准的做法。以下是全面总结:


核心论点

测试的初衷是为了提升代码质量,但过度、不必要且不可靠的测试不仅无法实现这一目标,反而会降低代码质量、增加工作量,并大大拖延项目进度。

王垠的立场是 他确实写测试,但以更聪明、更选择性的方式。他不提倡 Test-Driven Development (TDD)。


关于测试的 11 条原则

1. 态度和口号无法提升代码质量。
了解“unit test”和“integration test”等术语,并不意味着你会编程。提升代码质量的唯一可行方式,不是写测试,而是反复锤炼自己的思维,写出简单明了的代码。

2. 真正的编程大师不受测试束缚。
测试就像赛道上的护栏。一个合格的司机绝不会把注意力放在护栏保护上——他们的安全只取决于自己的技术,而不是护栏。提倡测试驱动开发的人就像三流司机:无论写多少测试,都无法产出可靠的代码。

3. 程序和算法确定之前,不要写测试。
过早写测试会束缚你的手脚,阻止你自由修改代码和算法。只有程序不再需要大幅改动时,才逐渐添加测试。

4. 不要为了迎合测试而改变清晰的代码。
为了满足“coverage”要求或使用 mocks,许多人将原本简单明了的代码改造成更复杂、更混乱的形式,甚至使用大量 reflection。这实际上降低了代码质量。

5. 不要测试实现细节——只测试本质属性。
测试应该只描述程序需要满足的“基本属性”(如 sqrt(4) 应该等于 2),而不是描述“实现细节”。测试实现细节本质上是把代码写了两遍。

6. 并非每个 bug 修复都需要测试。
在写测试之前,要仔细思考:这个 bug 在同一个地方再次发生的可能性有多大?一旦低级错误被识别,它不太可能在同一处重现。你应该为代码的本质而写测试,而不是为 bug 写测试。

7. 避免使用 mocks,尤其是多层 mocks。
多层 mocks 往往无法生成足够多样的输入,也无法覆盖各种边界条件。如果你的代码足够模块化,你就不需要多层 mocks 来测试它。

8. 不要忽视手动测试。
过度强调测试自动化不仅拖延项目进度,还丧失了手动测试的准确性。换一种思维方式,只需几分钟手动观察,就能发现许多深入问题。

9. 避免过长且耗时的测试。
有些人可以用小输入测试所需属性,但总喜欢给大输入,下意识认为这样更可靠。结果每次测试都消耗大量构建时间。

10. 每个测试只测试一个方面。
如果一个测试只测试一个方面,且不重复测试同一组件,那么根据失败的测试,你就能快速找到有问题的组件和位置。

11. 避免通过字符串比较进行测试。
比较格式化字符串输出的测试非常脆弱,因为格式往往会稍作改变。正确的方法是进行结构化比较。


案例研究

Google (PySonar):
王垠在 Google 创建 PySonar 时,没有遵从队友从一开始就写测试的要求。他以自己的方式组织代码,进行精确的思考和推理,在三个月内完成了一个非常优雅、正确、高性能且易维护的系统。PySonar 仍是世界上最先进的 Python 类型推断和索引系统,被许多公司采用来处理数百万行 Python 代码。

Shape Security:
他构建了一个先进的 JavaScript 混淆器,并改进了一个集群管理系统。对于集群系统,团队决定完全放弃现有的测试,转而依赖严格的代码审查、逻辑推理和审议。项目在不到两个月内完成。

Coverity(失败案例):
Coverity 的 Java 分析团队深受测试教条主义之苦——每个 bug 修复都需要测试,即使是显而易见的低级错误。这使得项目进度极其痛苦且缓慢,而产品仍然满是 bug。


结论

由于绝大多数人对测试存在如此深刻的误解,测试教条主义又如此普遍,许多优秀程序员沉迷于繁琐的测试驱动开发,无法施展才华。希望大家在项目中理性对待测试,而不是盲目写测试。只有这样,项目才能更好地、更快地完成。


简而言之: 王垠的文章是对软件工程中盲目测试文化的尖锐批判。他提倡 精确思考、干净代码和选择性测试,而非机械遵守 TDD 或 coverage 驱动的测试教条。

参考文献:


Back Donate