摘 要:在软件需求增加和规模增大,却又要能做出及时交付给用户并且让用户满意的软件的时期,传统的软件工程方法显得有些力不从心,且已经遭到人们的质疑.而最近兴起的一种软件开发过程相关的技术,提供一些比较高效、实用的软件过程开发方法,这就是敏捷软件开发方法。测试驱动开发TDD(Test-Driven Development)是极限编程过程(一种敏捷开发)的重要特征,其对控制软件开发进度和开发质量有非常重要的作用。它的基本思想就是在开发前根据对将要开发的程序的要求,先写好所有测试代码,并且在开发过程中不时地通过运行测试代码来获得所开发的代码与所要求的结果之间的差距。这些活动的进行很大程度上依赖着程序的断言代码。因此断言代码的全面性及完整性深深地影响着一个程序的开发进度和质量。
关键词:测试驱动开发;断言;十瓶保龄球
1 测试驱动开发的作用
作为敏捷软件开发的精髓,在软件开发过程当中对软件的质量起了很好的保护与促进作用,特别是对后期的软件设计修改等,节省了大量的开发时间,也可以有效的避免过度设计带来的浪费,可以让开发者在开发中拥有更全面的视角。其中主要可以:
1、提高代码质量
2、有效地改善设计方式
3、改变传统的开发思想
2 测试驱动开发的局限性
在测试代码开发过程当中,由于开发具有针对性,可能只完成满足了测试的代码,而忽略了对实际需求的实现,同时会导致单元测试的覆盖度不够,比如:可能缺乏边界测试。这使得在实际的操作中,必须和非测试驱动开发采取同样的措施,当代码完成以后还需要补充单元测试,提高测试的覆盖度。以十瓶保龄球为例,全中与补中在某些不同的位置,会使得测试代码的内容各异,若没有细致的情景分析,很难最全面地测试到系统的各种情况,这样软件安全风险的增加在所难免。本论文中,就断言覆盖度不够的问题提出了断言计划驱动测试的观点,以改善测试驱动开发在边界测试中覆盖度不够的问题。
3 优化边界测试
3.1 十瓶保龄球规则
一局比赛由十轮组成,每轮10个木瓶竖立摆放。比赛者最多投掷两次来尝试击倒所有木瓶。木瓶全部击倒或两次投掷完成宣告一轮结束。一次击倒所有木瓶为全中,两次合起来击倒所有木瓶为补中。
全中分数为10分再加上接下来两次投掷击倒的木瓶数。补中轮分数为10分再加上接下来一次投掷击倒的木瓶数。其他论为本论投掷击中的木瓶数。
如果第十轮全中,比赛者再多投两次来完成全中计分,若为补中,再投一次来完成补中计分。总分为每轮分数之和。
下面是一位比赛者在比赛中描述得分情况的计分卡,在案例分析时将使用该计分卡:
图1:一次十瓶保龄球比赛积分卡
3.2 编写断言计划
编写测试代码用来驱动程序的开发,而编写断言计划则用来指导编写测试代码中的断言。
对不同情况采取细分策略。就保龄球比赛而言,存在三种情况,即普通投掷、补中投掷和全中投掷。同样,其他问题类似之,也可先将情况分解成几个子情况。之后再将子情况分解,一直分解到可以不需要再做分解,如图。
图2:案例情况细分示意图
本案例经过两次细分:
普通投掷:结果与投掷轮的位置无关,不须再细分。
补中投掷:在最后一轮补中与在中间轮补中情况区别对待,应分开测试。
全中投掷:在最后一轮全中、倒数第二轮全中和其他轮全中的处理方式不同,须分三种情况测试。
通过对细分策略的了解,十瓶保龄球比赛有下面一些情况:
(1)一轮投掷之和小于10,位于中间与最后一轮情形相同。
(2)补中,补中轮在中间。
(3)补中,补中轮在最后一轮。
(4)全中,全中轮在中间。
(5)全中,全中轮在最后一轮。
另外,当全中在第九轮且第十轮不为全中,则九轮之后肯定至少还有两次投掷,这就可以归为(4)号,若第十轮为全中,则在第九轮全中之后有三次投掷,这种情况也属于(4)情况,因此不把第九轮为全中的情况视为另外一种情况处理。同样,其他问题类似,可先将情况分解成几个子情况,然后对子情况进行分解,一直分解到最细子情况再进行处理。所以保龄球比赛的断言计划可编写为如下几步:
第一步:对于第一种情况,在一次比赛中投任意次,只要其中存在一轮不是补中或全中,在这轮投掷之后编写断言语句。
第二步:对于第二情况,只要在一次比赛当中包含了一次补中(位置不在最后一轮),并在这次全中和补中投掷之后编写断言语句就可以对这两种情况进行测试。
第三步:是针对第四种情况的全中而言,与第二步类似;
至于第三和第五种情况,可以在第九轮投掷之后保存好当前状态,分两种情况处理:
第四步:第十轮为补中。
第五步:第十轮为全中。
由于第四和第五的特殊性,可以针对这两种情况写两套断言。
3.3 编写断言
定义类game()为一次比赛,他的方法add(int pins)为一次投掷方法(pins为投掷击中的木瓶数),score()为获取当前分数的方法。根据断言计划我们编写断言代码,先根据给定的评分记录卡上的评分编写第一套断言:
Game g = new Game();
……
g.add(5);//第5次投掷
assertEquals(14,g.score());//针对断言计划的第一步
……
g.add(5);//第7次投掷
assertEquals(34,g.score());//针对断言计划的第二步
……
g.add(1);//第11次投掷
assertEquals(61,g.score());//断言计划的第三步
……
g.add(6);// 第19次投掷
assertEquals(133,g.score());//断言计划的第四步
第二套断言与第一套基本相同,只是部分投掷改为下面的代码:
g.add(10)// 第17次投掷
g.add(2); 第18次投掷
g.add(5); 第19次投掷
assertEquals(136,g.score());//断言计划的第五步
4 总结
测试驱动开发是通过测试来推动整个开发的进行,用测试保证软件的质量,其中断言的作用与地位相当重要,断言的覆盖度直接影响到软件的质量。断言计划的编写有效地提高了断言特别是在边界位置的覆盖率。在进行断言计划编写过程中,采取细分策略能很大程度上避免对不同边界的遗漏而导致覆盖率不够的情况。因此,为了代码的健壮性,覆盖全面的断言非常重要,在编写断言之前,编写好全面的断言计划同样重要。并且在开发过程中可以不断的完善。我们可以用测试驱动开发,同样也可以用断言计划来驱动测试。
参考文献:
[1]
(美)艾斯特尔斯(Astels,D.)著.崔凯译.《测试驱动开发:实用指南》.中国电力出版社,2004.9.
[2]孙平平,张小龙等译.《测试驱动开发(中文版)》.中国电力出版社,2007.6.
[3]Alistair CockBurn 著,俞娟 译,胡健 审校.敏捷软件开发
[4]刘赟,余金山.《测试驱动开发探讨》.电脑开发与应用,2006 年第19 卷第08 期
[5](英)Matt Stephens,(美)Doug Rosenberg 著,汪丰,赵浩 等译.重构极限编程-XP的实践与反思.清华大学出版社 2005.6
[6]Agile Software Development-Principle,Patterns,and Practices Robert C.Martin