第1章 测试驱动开发
我们都做过这样的事——写一大堆代码然后艰难地使它工作起来。也就是先建造再修正。测试是在代码写完之后的事情。测试总是一件后面加上来的事情,这也是我们过去唯一所知的方法。
这种很难预料的过程被亲切地称为“调试”(debugging),我们可能会在其中花掉半个小时。调试的过程在我们的进度中被“测试”和“集成”粉饰起来。它总是风险和不确定的来源。修改一个bug可能导致产生另一个,有时是一系列其他的bug。我们往往会统计这些数据来预测把bug全部修改掉还需要花多少时间。然后我们会去关注曲线的拐点,拐点上的趋势表明我们修改bug的速度终于超过了新引入并报出bug的速度。拐点说明我们几乎就要完成了——但我们永远不能确切地知道在代码的某个黑暗的角落里是否还躲着一个杀手级bug。
开发人员在瀑布模型开发的最后阶段往往忙作一团,与其等到那时才发现问题,质检部门不如在开始时就写一些回归测试以尽快发现那些问题。可我们还是经常会遇到意外:一个小小的错误可能要花上几天、几个星期甚至几个月才能发现。有些错误从未找到。
一些有远见的人看到了这里的潜在问题,他们发现短的开发周期产生的问题会少一些。他们发现积极的测试自动化可以节省时间和精力。这样就不再需要继续重复冗长乏味且错误百出的工作了。测试不一定非要花费出动一小队手工测试人员这样昂贵的代价。很快人们就发现了其中的边际效应(side effect):可以避免调试了。解决了项目进度变化的一个根本原因,那么就会出现更靠谱的项目计划。
著名的嵌入式大师Jack Ganssle提出集成和测试是软件开发的脉络。不过还不能这么说,起码在目前广泛流行的开发方式中还不是,但它们以后必须是。测试驱动开发(Test-Driven Development,TDD)就是其中一种方式—一种有效的方式,它可以把测试贯穿到软件开发的脉络中去,它是你代码的“Kevlar”防弹衣。
把TDD应用于嵌入式C语言开发有很多值得关注的地方,这就是本书的目的。在这一章里,你将从“万米高空鸟瞰”TDD。然后我们将把TDD应用到一个简单的C模块中。当然,这会引发很多疑问。这些疑问将在第2章回答。在开始之前,我们先来看一个著名的bug。如果用了TDD,这个bug可能就可以避免了。