💡 Key Takeaways
- The 3 AM Wake-Up Call That Changed How I Think About Testing
- Why Testing Feels Like Pulling Teeth (And Why That's Actually Your Fault)
- The 15-Minute Rule: Making Testing Feel Like Progress, Not Punishment
- The Goldilocks Zone: Testing Just Enough (And Not a Line More)
改变我对测试看法的凌晨3点的惊醒电话
我在星期二凌晨3:17被手机的震动惊醒。我们的支付处理系统出现故障,40000名客户无法完成他们的购买。当我慌忙赶到我的笔记本电脑前,背景里的咖啡正在煮,我发现了罪魁祸首:我在前一天晚上6点合并的看似无害的两行代码。没有测试发现这段代码。没有CI管道对此发出警告。它就像一枚瞄准我们收入流的鱼雷,畅通无阻地进入了生产环境。
💡 关键要点
- 改变我对测试看法的凌晨3点的惊醒电话
- 为什么测试像拔牙(而且这其实是你的错)
- 15分钟规则:让测试感觉像进步,而不是惩罚
- 黄金法则:测试刚刚好(而不是多出一行)
这次事故为我们造成了18万美元的销售损失,以及5万美元的紧急工程费用。但更重要的是,它教会了我一个我早该学到的道理:编写测试并不是因为它本身无聊——而是因为我们做错了。
我是Marcus Chen,我在软件工程领域有11年的经验,最近6年担任一家每年处理23亿美元交易的金融科技公司的技术负责人。我在职业生涯中编写了大约47,000行测试代码——是的,我实际上是通过git统计计算出来的——我发现,讨厌测试的团队和接受测试的团队之间的差异在于方法,而不是态度。
传统的观点认为测试就像使用牙线:每个人都知道他们应该去做,但这感觉像是一项需要推迟满足感的苦差事。我在此告诉你,这是一种错误的类比。正确的测试就像与未来的自己进行对话——这次对话可以让你免于凌晨3点的惊慌发作和六位数的错误。
为什么测试像拔牙(而且这其实是你的错)
关于为什么大多数开发人员觉得测试痛苦。在我对三个工程团队和87名开发人员进行的调查中,我发现73%的人指出“重复的样板代码”是他们的主要抱怨,而61%的人提到“测试内容不明确”是紧随其后的第二个问题。只有12%的人表示他们实际上喜欢编写测试,而这12%的人有一个共同点:他们开发了让测试感觉更像是解决问题而不是文档记录的系统。
“测试并不是因为它本身无聊,而是因为我们做错了。讨厌测试的团队和接受测试的团队之间的差异在于方法,而不是态度。”
根本问题在于我们把测试视为附加项——这是一种为了发布代码所支付的税。我们编写实现,使其正常工作,感受到看到它运行的多巴胺,然后对编写测试的前景发出呻吟。在那时,我们的大脑已经转移了注意力。我们已经在考虑下一个特性,下一个问题,下一个多巴胺的刺激。
这种反向的方法造成了几个问题。首先,你现在对已经工作的代码编写测试,这感觉是多余的。你的大脑知道这段代码是有效的——你刚刚看到它工作过——所以编写测试感觉像是一种忙碌的工作。其次,你已经做出所有设计决策,这意味着你的测试现在受限于潜在的不可测试架构。第三,你失去了伴随解决新问题而来的创造性精力。
我用这种方式编写测试花了三年时间,而我的测试覆盖率徘徊在40%左右。这并不是因为我懒惰,而是因为这个过程确实很痛苦。每个测试都感觉像是在将我已经读过的小说翻译成我几乎不会说的语言。突破发生在我意外地首先为一个特别棘手的身份验证流程编写测试时,我发现了一些让人惊讶的事情:这实际上比编写实现更令人愉悦。
原因是?当你首先编写测试时,你仍处于解决问题的模式中。你在设计API,考虑边缘情况,并做出架构决策。你的大脑参与到创造性工作中,而不是机械的文档记录。测试变成了一个规范,一个设计文档,一个安全网,三者合而为一。突然间,测试并不无聊——它是有趣的部分。
15分钟规则:让测试感觉像进步,而不是惩罚
这里有一个改变我与测试关系的技术:我从不花超过15分钟编写测试而不看到某个测试通过。这听起来可能有些任意,但背后有心理学。我们的脑袋是为即时反馈循环而设置的。当你花45分钟编写一个全面的测试套件然后再运行任何东西时,你是在和你的神经化学作斗争。
| 测试方法 | 时间投资 | 开发体验 | 生产事件 |
|---|---|---|---|
| 没有测试 | 0小时前期 | 开始时快速,后来压力大 | 高频率,高成本 |
| 仅人工测试 | 每个特性2-3小时 | 重复乏味 | 中等频率 |
| 样板代码测试 | 每个特性4-5小时 | 令人沮丧且缓慢 | 低频率,但测试易碎 |
| 战略测试 | 每个特性2-3小时 | 引人入胜且增强信心 | 非常低频率 |
| 测试驱动开发 | 每个特性3-4小时 | 令人满意的设计过程 | 最少事件 |
相反,我将测试分解为微循环。编写一个测试。让它通过。再编写一个测试。让它通过。每个循环花费5到15分钟,每个循环都给你一点小的成就感。在一个典型的6小时编码会话中,这样就能得到24到72个小胜利,而不是最后一个大的延迟满足感。
让我给你一个具体的例子。上个月,我正在构建一个根据需求、时间和用户历史计算动态定价的特性。与其编写整个定价引擎然后测试,不如从一个测试开始:“当需求低和时间处于非高峰时,价格应为基础费率。”这个测试花了8分钟编写并使其通过。然后是:“当需求高时,价格应增加20%。”再花12分钟。“当需求高并且时间处于高峰时,价格应增加35%。”又花了10分钟。
90分钟后,我有了11个测试和一个工作的定价引擎。更重要的是,我没有感到无聊。每个测试都是一个小谜题,实施过程自然而然地从测试中产生。相比于我的旧方法:编写定价引擎(60分钟),在浏览器中手动测试(20分钟),然后不情愿地编写测试(45分钟的纯乏味)。总的时间是相同的,但体验完全不同。
关键是保持反馈循环紧凑。如果你编写的测试需要30分钟以上才能完成,那你是在做错事。模拟外部依赖。使用内存数据库。并行执行测试。尽一切努力保持这个循环在15分钟以内。我见过团队通过积极的并行化和智能的模拟,将测试套件的运行时间从40分钟缩短到6分钟,对开发人员的幸福感产生了可量化的影响——我们的内部调查显示,“我喜欢编写测试”的回应增加了34%。
黄金法则:测试刚刚好(而不是多出一行)
我在职业生涯早期犯下的最大错误之一是追求100%的测试覆盖率,仿佛这是一种神圣的追求。我花了很多时间为getter和setter、无关紧要的实用函数以及如此简单以至于不可能出错的代码编写测试。我的测试套件膨胀到15,000行,而我的实际代码库只有8,000行。这个比例是荒谬的,更糟糕的是,这使重构变得极其困难。
“编写测试就像与未来的自己进行对话——这种对话可以让你免于凌晨3点的惊慌发作和六位数的错误。”
我了解到的事实是:测试覆盖率存在一个黄金法则,而不是100%。对于大多数应用程序,它在70%到85%之间。如果低于70%,你将留下太多关键路径未测试。如果超过85%,你正在测试实现细节,这使得你的代码库变得脆弱且难以更改。
我现在遵循我称之为“风险加权测试”的方法。并非所有代码都是平等创造的