1、VTDD(可视化测试驱动开发)技术白皮书广州凯乐软件技术公司2010 年 6 月1内容介绍如果您的项目面临这些问题:开发费用和进度失控、可靠性差、难以维护;如果您期望改进开发过程,改变被动现状,但一直很忙顾不上,请考虑使用 VTDD。TDD(Test-Driven Development,测试驱动开发) ,具有明确需求、明确设计、测试即文档、代码质量可控、提高开发效率等优点,但也具有资源利用不充分、自动化程度低、干扰编程思维等缺点。VTDD(Visual TDD),可视化的 TDD,是 TDD 的改进和升级。VTDD 继承了 TDD的优点,克服了 TDD 的缺点。VTDD 的改进可归纳为 “三
2、化 ”:可视化、自动化、现实化。可视化:开发过程中,程序行为可视。自动化:由工具自动完成隔离补齐、测试代码生成、数据表格化、底层模拟、覆盖统计、协助找出遗漏数据等工作。现实化:VTDD 分为三级,其中,第一级(VTDD1)基于现有流程、可在项目周期的任意时段引入,且不影响进度。企业项目普遍周期紧张,顾不上流程改进,想等“有空”时再说。然而代码质量不可控,正是开发周期不可控的主因,当前项目延期,又会造成下一个项目更紧张,总是“没空” 。TDD 的一个重要优势是易于引入,不影响当前项目的编码进度,并大幅缩短使产品稳定下来的时间,减少总的周期,缓解总是很紧张的局面,特别适合于总是“没空”的企业。本白
3、皮书介绍 VTDD 基本概念和特性,并演示 VTDD 过程,提出相关工具要求,指出 VTDD 实施策略,最后介绍实施 VTDD 的几点建议。1VTDD 概述TDD(Test-Driven Development,测试驱动开发) ,是一种具有突出优点的软件开发、设计和测试方法。TDD 的基本思路是测试先行,通过测试来推动开发的进行。TDD的重要目的不仅在于通过测试使产出的代码质量可控,还在于在开发过程中帮助程序员去除模棱两可的需求。TDD 具有明确需求、明确设计、测试即文档、代码质量可控、提高开发效率等优点,但也具有不可忽视的缺点:自动化程度低:编写测试代码的时间,大致相当于开发产品代码的时间。
4、对于大型项目的并行开发,还面临隔离、补齐、内部输入等问题,人工解决这些隐含问题的时间,往往不少于编写一般测试代码的时间。资源利用不充分:单元测试的输出可以完整描述程序的行为,这是一种宝贵资源,TDD 忽略了这一点。程序行为就是在什么输入下,会执行哪些代码,会产生什么输出。如果程序行为一目了然,测试对于开发的驱动效益将翻倍。干扰编程思维:灵感、创意、思路是脆弱、易失的,编程工作需要连贯的专注。TDD过程中,测试所耗费的时间往往是开发时间的一至两倍,且与编写产品代码交替进行,难免影响编程思维的连贯性。干扰思维可能会造成程序员本能的抵制,使 TDD 难于推广、难于长期坚持。VTDD(Visual T
5、DD),即可视化的 TDD,是 TDD 的改进和升级。VTDD 继承了TDD 的优点,克服了 TDD 的缺点。改进可归纳为“三化”:可视化、自动化、现实化。可视化:开发过程中,程序行为可视。可视化降低编程劳动强度,并大幅提升编码效率,中等复杂度的函数,编写效率提高一倍以上,复杂度越高,效率提升比例越大。自动化:由工具自动完成隔离补齐、测试代码生成、数据表格化、底层模拟、覆盖统计、协助找出遗漏数据等工作。人的工作主要在于:在数据表格中列出程序功能点,这是明确需求、明确设计、促进开发的过程。测试时间成本趋向于零。现实化:VTDD 分为 VTDD1(自然级)、VTDD2(重构级)、VTDD3(敏捷级
6、)。自然级基于现有流程、可在项目周期的任意时段引入,且不影响进度。此后可逐步提升到重构级和敏捷级,进一步改进开发流程, “先固化,再优化” 。您的项目是否面临这些问题:开发费用和进度失控、可靠性差、难以维护?如果您期望改进开发过程,改变被动现状,请不要等待,立即引入 VTDD。项目越紧张,越需要尽快改进开发方法。等“有空”时再改进是不现实的。代码质量不可控,正是开发周期不可控的主因,拖延下去,只会使问题累积。当前项目的延期,会造成下一个项目更紧张,更不会“有空” 。请您想一想,去年这个时候紧不紧张?前年呢?什么时候轻松过?如果不做出改变,明年这个时候,后年这个时候,一样还会很紧张,恐怕永远等不
7、来“有空” 。项目周期越紧张,越需要让新产出的代码质量可控,这样才能换来进度可控,项目才有可能按计划完成。只有行动,立即行动,才可能换来宽松和从容。2但是, “先顾眼前” ,也是不得已的选择。VTDD 既不影响眼前,效果也立竿见影。假如一个项目,编码周期为四个月,在第二个月引入 VTDD1,当月进度不减,此后两个月,进度可以加快大约 15-30%,更重要的是,产出的是经过充分测试的代码,可以避免代码质量不可控造成的开发周期不可控,大幅缩短使产品稳定下来的时间。总的来说,引入VTDD,不但保证代码质量,而且,项目所耗费的人月可以减少大约 30-50%,缩短开发周期,在“快鱼吃慢鱼”的市场竞争中赢
8、得先机。VTDD 过程-可视化下面用一个简单示例,展示 VTDD 一般过程。我们要编写一个函数,其功能是删除字符串左边空格。步骤一,编写函数框架,能通过编译就行:char* strtrml(char *str)return str;步骤二,明确代码的最基本功能,就是确定程序最普通的输入是什么,应该产生什么输出。下图是填写最普通输入输出的界面,这也是第一个用例,填写完成后,工具就可以生成测试代码,并且将数据移到表格中。3步骤三,进一步明确代码功能,就是确定代码的各个功能点,把想到的输入分类都列出来,并且指定对应的正确输出。下图是生成数据的界面和数据表格。步骤四,编写代码。VTDD促进开发的最主要
9、效益在于程序行为可视。编写几行代码、就可以查看程序行为,然后修改错误、继续编写,直到测试全部通过。假设编写strtrml()的思路是:首先计算左边空格的数量,然后再把字符串朝左边移动。先编写计算左边空格数量的代码(粗体且带下划线的为新增代码):char* strtrml(char *str)int count = 0; /左边空格数量while(*str+ = )count+;return str;每当想看看代码会做什么时,就可以编译当前源文件,通过编译后,测试自动执行,并显示测试结果,下图是上面的代码产生的行为:4如果想看看左边空格数计算结果对不对,由于这是局部变量,在内部动态变化,所以需指
10、定打印。指定方式有两种:一是在测试工具中指定,好处是不污染产品代码,二是在产品代码中指定,好处是维护比较自由。这里采用第二种方式:char* strtrml(char *str)int count = 0; /左边空格数量while(*str+ = )count+;/int,countreturn str;程序行为如下图,可以看到,左边空格的计算结果是正确的。5接下来继续编写代码,把字符串朝左边移动:char* strtrml(char *str)int count = 0; /左边空格数量while(*str+ = )count+;/int,countwhile(*str)*str = *(
11、str+count);str+;return str;现在已经完成移动了,结果对不对呢?看看程序行为:6结果是完全不对的。未出现红色代码,表示当前输入执行了全部代码。查看代码可以发现,在计算左边空格后,指针已经偏移,移动操作针对的是已偏移后的指针,且再次使指针偏移,结果当然不对了。所以要先把指针保存,每次偏移后恢复:char* strtrml(char *str)char* ptr = str;int count = 0; /左边空格数量while(*str+ = )count+;/int,countstr = ptr;while(*str)*str = *(str+count);str+;s
12、tr = ptr;return str;7程序行为如下图:现在可以看到,输出已经正确,再看用例的测试结果,6 个用例,只报告了一个异常,其他都已经通过。点击异常信息,对应的程序行为如下图:输入为空指针时,产生了异常,代码未判断和处理空指针。用例数据中,并无空指针输入,这是工具自动添加的用例。在产生异常的代码前加上判断空指针的代码:if(str = 0) return str;,测试即可全部通过。从上图可以看出,一种输入下,往往只执行部分代码,程序行为不仅仅在于产生了什么输出,还包括执行了哪些代码,即程序行为=输入+所执行的代码+输出。到这里,代码写完了,测试工作也同步完成。在这个过程中,付出了
13、什么?获得了什8么?所付出的是明确程序功能的步骤二和步骤三,即根据程序的设计功能将输入输出数据列出来,这不需要多少时间,因为在编写代码前,程序员本来就需要想清楚这些,只不过用这种简单的方式记录下来而已。所获得的主要有三点:1) 在编写代码过程中,程序行为一目了然。写代码很难一气呵成,要频繁回顾上下文,但代码与文字不同,它的真正意义在于执行起来会做什么,这是眼睛看不出来的,需要在头脑中推理。推理是隐性的但高强度的脑力劳动,VTDD省略了这种推理,减轻了头脑的负担,能够比较轻松地整理思路,思路有偏差的时候,能够及时做出调整,这可以大幅提升编码效率,并降低劳动强度。2) 基本上免除调试,调试是最花费
14、时间的。VTDD 与TDD不同,首先关注的是程序行为而不是测试是否通过。很多函数,一个功能点的实现就需要大量代码,甚至代码基本写完时,第一个用例才能通过,在这个过程中,关注测试是否通过没有意义。VTDD可以更频繁地执行测试,在最短时间内发现错误并改正,且程序行为已经很清楚了,基本上不再需要调试。3) 测试与开发同步完成。传统开发模式下,很多程序员都将单元测试视为包袱,而VTDD使单元测试变成开着走的 “车子” ,而不是背着走的 “包袱” 。VTDD并不要求测试所有代码,程序员可以只在编写有一定复杂度的函数时,才使用VTDD,这种时候,程序行为可视化对编码过程帮助很大,形成强烈的吸引力,使单元测
15、试由“要我做”转换为“我要做” 。无处不在的80-20规则,在软件开发中同样存在,也就是说,80%的编程时间消耗在20%的代码上,这20%就是功能逻辑复杂的代码。当一个函数的功能比较复杂的时候,VTDD可以节约一半以上的编码时间,复杂度越高,效率提升越大。假如我们只在编写这20%代码时,使用VTDD ,理论上可以提升编码进度40%以上。排除阅读资料、中间休息、会议等时间,实际上可以提升进度15-30%。VTDD 更大的效益在于产出的代码质量可控,使后期调试排错的时间减少60-80%。总的来说,引入VTDD,项目所耗费的人月可以减少大约30-50% 。由于软件开发无法做到同条件重复比较,难于得出
16、精确的实验数据,上述数据只是根据经验得出的大致估计,您可以通过体验和评估来得出自己的数据。先写产品代码的框架,会不会有违测试先行的理念?当然不会。在编写一个类的测试代码前,难道不需要在心里想清楚类名是什么,父类是什么?在编写一个函数的测试代码前,难道不需要想清楚函数原形是什么?如果这些不确定,如何编写测试代码?在心里想清楚和写出来有本质区别吗?所以,先把这些确定的东西写出来,并不违背测试先行的理念,而好处很明显:工具可以根据代码框架自动生成测试代码。VTDD 的工具要求-自动化前面介绍的只是一个简单的例子,能应用于实际项目吗?在实际工作中,事情远比这个复杂,还有一些问题需要解决。VTDD 的自动化,除了自动生成测试代码外,更重要的,