第1章 MILY: '微软雅黑','sans-serif'">序言
1. 自信的编码
有一次——或许就是上个礼拜二——有两个开发者:Pat 和Dale。他们面临着相同的最后期限,而这一天也越来越近了。Pat 每天都在着急地编写代码,写完一个类又写一个类,写完一个函数又接着写另一个函数,还经常不得不停下来做一些调整,使得代码能够通过编译。
Pat 一直保持着这种工作方式,直到最后期限的前一天。而这时已经是演示所有代码的时候了。Pat 运行了最上层的程序,但是一点输出也没有,什么都没有。这时只好用调试器来单步跟踪了。“Hmm,决不可能是这样的”,Pat 想,“此时这个变量绝对不是0 啊”。于是,Pat 只能回过头来看代码,尝试着跟踪一下这个难以琢磨的程序的调用流程。
时间已经越来越晚了,Pat 找到并且纠正了这个bug;但在这个过程中,Pat 又找到了其他好几个bug;如此几次过后,bug 还是存在。而程序输出那边,仍然没有结果。这时,Pat 已经筋疲力尽了,完全搞不清楚为什么会这样,认为这种(没有输出的)行为是毫无道理的。
而于此同时,Dale 并没像Pat 那么快地写代码。Dale 在写一个函数的时候,会附带写一个简短的测试程序来测试这个函数。这里没有什么特殊的地方,只是添加了一个简单的测试,来判断函数的功能是否和程序员期望的一致。显然,考虑如何写,然后把测试写出来,是需要占用一定时间的;但是Dale 在未对刚写的函数做出确认之前,是不会接着写新代码的。也就是说,只有等到已知函数都得到确认之后,Dale 才会继续编写下一个函数,然后调用前面的函数等等。
在整个过程中,Dale 几乎不使用调试器;而且对Pat 的模样也有些困惑不解:只见他头埋在两手之间,嘀咕着各种难听的话语,咒骂着计算机,充血的眼球同时盯着好几个调试窗口。
最后期限终于到了,Pat 未能完成任务。而Dale 的代码被集成到整个系统中,并且能够很好地运行。之后,在Dale 的模块中,出现了一个小问题;但是Dale 很快就发现了问题所在,在几分钟之内就解决了问题。
现在,是该总结一下上面这个小故事的时候了:Dale 和Pat 的年纪相当,编码能力相当,智力也差不多。唯一的区别就是Dale 非常相信单元测试;对于每个新写的函数,在其他代码使用这个函数并对它形成依赖之前,都要先做单元测试。
而Pat 则没有这么做,他总是“知道”代码的行为应该和所期望的完全一样,并且等到所有代码都差不多写完的时候,才想起来运行一下代码。然而到了这个时候,要想定位bug,或者,甚至是确定哪些代码的行为是正确的,哪些代码的行为是错误的,都为时已晚了。
2. 什么是单元测试
单元测试是开发者编写的一小段代码,用于检验被测代码的一个很小的、很明确的功能是否正确。通常而言,一个单元测试是用于判断某个特定条件(或者场景)下某个特定函数的行为。例如,你可能把一个很大的值放入一个有序list 中去,然后确认该值出现在list 的尾部。或者,你可能会从字符串中删除匹配某种模式的字符,然后确认字符串确实不再包含这些字符了。
执行单元测试,是为了证明某段代码的行为确实和开发者所期望的一致。
对于客户或最终使用者而言,这种测试必要吗,它与验收测试有关吗?这个问题仍然很难回答。事实上,我们在此并不关心整个产品的确认、验证和正确性等等;甚至此时,我们都不去关心性能方面的问题。我们所要做的一切就是要证明代码的行为和我们的期望一致。因此,我们所要测试的是规模很小的、非常独立的功能片断。通过对所有单独部分的行为建立起信心,确信它们都和我们的期望一致;然后,我们才能开始组装和测试整个系统。
毕竟,要是我们对手上正在写的代码的行为是否和我们的期望一致都没把握,那么其他形式的测试也都只能是浪费时间而已。在单元测试之后,你还需要其他形式的测试,有可能是更正规的测试,那一切就都要看环境的需要来决定了。总之,做测试如同做善事,总是要从家(代码最基本的正确性)开始。
3. 为什么要使用单元测试
单元测试不但会使你的工作完成得更轻松,而且会令你的设计变得更好,甚至大大减少你花在调试上面的时间。
在我们上面的小故事里面,Pat 因为假设底层的代码是正确无误的而卷入麻烦之中,先是高层代码中使用了底层代码;然后这些高层代码又被更高层的代码所使用,如此往复。在对这些代码的行为没有任何信心的前提下,Pat 等于是在假设上面用竖立卡片堆砌了一间房子——只要将下面卡片轻轻移动,整间房子就会轰然倒塌。
当基本的底层代码不再可靠时,那么必需的改动就无法只局限在底层。虽然你可以修正底层的问题,但是这些对底层代码的修改必然会影响到高层代码,于是高层代码也连带地需要修改;以此递推,就很可能会动到更高层的代码。于是,一个对底层代码的修正,可能会导致对几乎所有代码的一连串改动,从而使修改越来越多,也越来越复杂。于是,整间由卡片堆成的房子就由此倒塌,从而使整个项目也以失败告终。
Pat 总是说:“这怎么可能呢?”或者“我实在想不明白为什么会这样”。如果你发现自己有时候也会有这种想法,那么这通常是你对自己的代码还缺乏足够信心的表现——你并不能确认哪些是工作正常的而哪些不是。
为了获得Dale 所具有的那种对代码的信心,你需要“询问”代码究竟做了什么,并检查所产生的结果是否确实和你所期望的一致。
这个简单的想法描述了单元测试的核心内涵:这个简单有效的技术就是为了令代码变得更加完美。
文章来源于领测软件测试网 https://www.ltesting.net/