6、增强调试器功能
如果测试代码由工具自动生成,可以考虑通过加强测试代码的功能,来间接增强调试器功能,具体来说,以下功能是很有价值的:
自动选择调试输入:捕捉合适的调试输入通常需要高级断点,有时是很麻烦的,如果由测试工具来选择某个测试用例作为调试输入,那么又可以省下不少时间。
后退和重复:调试器一般不支持后退,但测试代码可以实现模拟后退,例如,当到达测试代码尾部时,自动检查是否处于调试状态,如果是,则返回测试代码入口重新执行,这样,调试时只要使用"执行到光标所在行"之类的调试器命令,就可以实现后退和重复。由于每个测试用例都是独立的,重新执行时会建立新的被测试对象,因此,后退时,成员变量、参数、局部变量都能实现真正的后退,全局变量和静态变量则不能后退(幸运的是,这两种变量在一般函数中用得不多)。可以实现无限制的后退与重复,调试结束时关闭调试器就行了。
调试过程中切换输入:有时,需要比较不同输入时某个变量的值,如果调试过程中可以切换输入,岂不妙哉?综合使用"自动选择调试输入"和"后退和重复"即可做到调试过程中切换输入。
增强编辑继续功能:"编辑继续"功能对已执行过的代码通常是无效的,但利用后退和重复功能,可以让"编辑继续"功能发挥更大的效能。
7、实现零时间彻底测试
之前我们讨论了实现彻底测试的"三步法",本文讨论了减少测试时间及挖掘编码调试中的效率潜力,用减少编码调试时间来抵消测试时间,从而实现零时间彻底测试。
单元测试和编码调试有紧密的关系,边编码边测试,实现编码调试测试一体化,可以避免重复工作,最大限度地提高开发效率。如果测试工具实现了本文所述的全部技术,那么,做到"零时间彻底测试"是不成问题的,甚至可以进一步缩减编码阶段的工期,我们来比较一下"测试耗费的时间"及"测试所节约的时间",看看哪一个更多些:
假如测试工具实现了前述的所有技术和方法,那么:
测试方面:
第1步,自动生成测试代码,只要填写输入输出数据就可以建立第一个测试用例,其他用例采用拷贝修改的办法建立。这一步只需建立容易想到的用例,不必考虑是否遗漏,因此,这一步费时是很少的;
第2步,由工具自动统计白盒覆盖率,自动画出逻辑结构图,并标示未覆盖的逻辑单位(语句、条件、分支、路径),用户选择一个未覆盖的逻辑单位,系统自动从现有的测试用例中计算出一个近似用例,并生成一些提示,依据提示修改一个输入数据及预期输出,即可建立预期的测试用例。如果逻辑单位不可覆盖,也能根据修改提示判断出来并从逻辑结构图中删除。这一步是"拾遗",即找出遗漏的测试用例,这种用例的数量通常不多,因此耗时也不会太多;
第3步,由工具自动生成大量测试用例,捕捉编码时未考虑某些特殊输入形成的错误。这一步通常不需要消耗什么时间。
再来看看能够从编码调试中挖出来的时间:
通过描述程序行为,帮助整理和完善编码思路,提高编码效率;
通过描述程序行为,帮助快速找出错误原因,减少单步调试;
通过增强调试器功能,提高调试效率。
编程工作的主要时间消耗在于编程思路和调试,上述功能从这两方面入手,所节约的时间是相当可观的,当编写比较复杂的代码时,所节约的时间可能比测试所消费的时间多得多,不但能实现零时间测试,而且还可能缩短编码工期。
8、舒适高效地开发
在原来用于编码的时间内同时完成编码和单元测试,会不会增加程序员的劳动强度?不会的,因为:
1)找出并消除局部代码中的错误,本来就是程序员的份内工具,并不是额外工作;
2)编程最累人的是调试,翻江倒海地找一个小小Bug的经历,相信每个程序员都有过,不但累人,而且气人,充分的单元测试使这种情形几乎不会出现;
3)编程工作中比较累人的还有清理思路,一般环境下要了解程序行为并不容易,这对程序员完善编程思路很不利,如果通过测试工具来描述程序行为,使程序行为一目了然,不但提高工作效率,还会感觉比较舒适。
程序员的工作目的是解决问题,工作乐趣也在于解决问题,最忌的是注意力被分散和思维被干扰。本文介绍的单元测试技术,测试工作的大部分由工具完成,不会分散注意力和干扰思维,并通过描述程序行为等手段,帮助程序员专注于问题的解决,更好地发挥潜能,也使工作更有乐趣。