测试是程序员的护栏,但不是每段代码都需要护栏。判断在哪里架设护栏,比一直架设更重要。
何时该写测试
当代码复杂且需要保障稳定性时
复杂的算法实现和核心业务逻辑必须测。这类错误的特点是:发生概率低,但一旦发生损失大。
银行交易系统每秒处理上万笔转账,任何一笔的数字错误都可能造成资损。这种场景下,测试的收益是清晰的:写测试的成本 << 不写测试的期望损失。
测试的作用不是证明代码正确,而是降低代码变更时的信心成本。当你修改一段复杂逻辑时,有测试和没测试是完全不同的心理状态。
当代码需要被多人长期维护时
团队成员水平参差不齐,代码被易手的频率高。测试是跨越时间传递设计意图的介质。
新来的开发者读不懂旧代码,但他能看懂测试。测试告诉你:这个函数的预期输出是什么,边界条件是什么,错误情况怎么处理。
何时不该写测试
当项目初期需要快速迭代时
验证想法阶段不需要测试。这个阶段的代码大概率会被重写,测试是给不存在的东西交的税。
一个 MVP 上线前花两周写测试,结果发现方向错了,测试全部白写。这是创业初期最常见的浪费。
判断标准:这段代码预计会被重写吗?预期生命周期有多长?生命周期短的代码,不值得测试。
当项目规模较小且功能单一时
三个人天的项目,代码总量不超过五百行。这种情况下写测试的工作量和收益不成比例。
不是不测,而是测得更有针对性。只测那些:逻辑复杂容易出错、错误难以发现、崩溃后果严重的部分。
开放性思考
测试不是目的,系统的可信性才是。
测试只是一种建立可信性的手段。还有其他手段:Code Review、类型系统、形式化验证、监控报警。它们各有各的成本和适用范围。
在真实项目中,往往是多种手段组合使用。选择哪些组合,取决于:系统规模、团队组成、变更频率、容错要求。
一个优秀的工程师,不是写测试最多的那个,而是最清楚在什么地方不写测试的那个。