程序员如何保证自己开发的正确性——测试开发有感

TDD系列

Posted by Bruce Wong on May 21, 2022

最近因为工作需要,从事搬砖的时间要明显多于以往,所以有机会接触并思考工程实践的落地,以及它对实际工作的影响。今天想分享一下本周发生的让我觉得是“AHA Moment”的时刻。

咦!这块代码居然从来没走到过

这句感叹让我当时也很惊讶。说一下背景,因为最近的工作内容,需要使用其他团队提供的API,虽然API已经提供一段时间了,但是我是刚刚接手的这个系统,所以希望能对API所提供的行为能有一个全面的认识,一方面是学习API,另一方面也可以Review一下当前系统使用API的地方的行为是否符合预期。我使用xUnit框架对API编写了若干测试。好处是:

  • 一方面学习API。
  • 另一方面增加一层防护网,一旦API有变化对我的业务造成影响,可以第一时间知道。

因为没有文档,所以我就约API Team的一个开发一起结对开发,我写测试,他来描述期待行为,如果不清楚的时候查看代码。“AHA Moment”是出现第一条错误测试发生的时候,他查看代码,告诉我肯定的答案。结果发现居然和他说的不同。他看着我的测试反复查看code之后发现这条本以为设计为了当前这条测试的代码居然永远走不到!而所有维护这个API的开发都会认为这条代码的作用就是处理当前这种情况。当时我俩都很惊讶,因为如果不是像今天这种结对和写测试,可能永远不会发现。当然你可能会说,那可能也不会出现问题,因为永远不会执行。我的个人感觉是:

  • 永远不执行的代码可以算是一种浪费,他当初就不应该被写出来,也可以算一种过度设计吧。
  • 虽然没有被执行但是设计的人认为他应该应对某种场景的时候,这就形成了系统潜在风险。这种风险的影响可大可小。

这次持续30分钟的结对,我们共发现4个API的Bug。而这些Bug已经在系统存在一段时间了。

Echo: 不写测试,程序员如何保证开发内容的正确性呢?

重构的底气

除了对使用的API进行测试编写,我还对当前维护的功能编写了一些测试,因为系统是已存在的,之前并没有基于TDD开发,所以我编写的都是集成测试,但是会利用xUnit这种单元测试框架进行断言来对预期行为做判断。感兴趣的小伙伴可以看我的上一篇文章。截止到本周,我差不多编写了80个左右的测试,基本覆盖了主要功能场景。我记得一个月前,当我询问另一个开发人员是否可以重构某一个函数的时候,他的回复是:尽量别修改,因为你无法保证是否会影响其他地方。或者加一个if else 保留这段后再调用你的新方法。而现在我可以很从容的修改掉这段讨厌的“坏味道”,因为我可以直接运行80多个case,只要他们都通过,至少我有90%的信心没有改坏系统。你要问我剩下的10%怎么保证?哈哈,再多写一些测试吧!
“AHA Moment”就是当我提心吊胆的点击“Run All Tests”之后看到全绿的“Pass”的时候你感受到的信心和的喜悦。

Echo: 不写测试,程序员如何保证开发内容的正确性呢?

写在最后

推行TDD最大的难度是大家觉得浪费时间,任务压力大,写测试不如直接写功能代码来的高效。另一方面结对编程用两个人来做一件事情效率折半。但是反直觉的是,当你结对编程的时候你会发现两个人的讨论和思考会带来更高质量的代码。就像上面分享的AHA Moment——30分钟发现4个Bug。高质量的代码能带来什么影响,我相信不用多说了。
另一个难跨越的一步是很多系统已经存在很久了,代码不可测,如何推进TDD。其实技术手段有很多,关键点不是写什么类型的测试,而是用测试的思维方式构建一张可以自动运行的安全网来验证我们的工作,而不是都是靠猜测。除了单元测试,集成测试、GUI测试、BDD这些都是技术上能够自动化运行的,同时可以用于已存在系统,只是运行成本都比单元测试要高。但是从今天分享的两个案例来看,有和没有测试会给你带来不一样体验的。
面对代码的坏味道,我们是无可奈何地纵容,还是想有见一个消灭一个的魄力,底气从何而来?真心希望小伙伴们可以鼓起勇气迈出编写测试代码的第一步。相信从0到1你会找到很多属于你的“AHA Moment”的。

践行敏捷实践,让工作变得更美好。欢迎关注我的公众号,交流落地经验。