浅析测试驱动开发
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
浅析测试驱动开发
测试驱动开发是一种用于敏捷软件开发的开发过程,可以快速应对需求变化。
它要求先设计和编写测试代码,然后编写功能代码通过所有测试,再重构以提高代码质量。
文章将先介绍测试驱动开发的优点、使用环境,然后介绍开发过程,最后介绍相关工具。
标签:测试;TDD;敏捷开发
1 概述
1.1 定义
测试驱动开发(Test Driven Development,TDD)是由极限编程之父Kent Beck提出的一种面向对象的开发方法[1]。
区别于传统的软件开发模式,测试先行将更重视测试在整个软件开发过程中的作用并促进项目的进行。
它要求先完成测试代码,然后编写功能代码,并且功能代码要以通过测试代码为标准,然后对功能代码重构,重构之后再运行测试并要通过测试[2]。
它的一个开发周期比较短,整个项目是多个周期的迭代。
这种开发方式有效的提高了软件质量和开发效率[3]。
目前,TDD已经被很多公司和开发团队接受并用于实践。
1.2 优点
由于测试先行,因此写代码前就应该有明确的需求,并体现在测试用例中。
在交付前,测试用例可以用来描述功能需求并替代部分文档。
并且以测试用例描述的需求不容易出现模糊不清的概念,因为测试结果只会是True或False。
这解决了开发人员在开发时误解或由于沟通问题不完全理解需求文档而造成开发到一定程度后才发现代码与需求有偏差。
但这还没有解决对客户的误解或与客户沟通不畅导致需求分析错误的问题。
功能代码编写完成后必须通过所有测试,这就保证了这部分代码是满足其功能要求的。
通过确保每小部分代码的质量,可以较快的叠加成更复杂的功能且保证最后交付的软件与设计的要求是一致的。
在对功能代码进行优化时,因为也要通过测试用例,所以能保证这部分代码的改动不会对调用它的其他模块有影响。
1.3 适用环境
尽管从理论上讲TDD可以在各种软件开发项目中使用,但是在某些项目上可能感觉不到比较明显的效率提升或质量提高。
TDD是面向对象的开发方式,如果项目不使用面向对象的设计和开发,则不适合使用TDD。
GUI等难以进行单元测试或进行测试比较麻烦的部分也不适宜使用TDD的开发方式。
因为TDD是以测试驱动的,虽然测试是软件交付内容的一部分,但是如果测试部分的难度大于软件功能的开发,且消耗更多的时间,那么就无法再提高整个项目的开发效率。
TDD还对设计有很高的要求。
设计的结果直接影响到测试用例,如果测试用例没有被很好的设计,会严重影响软件的开发。
2 应用
2.1 开发流程
2.1.1 设计
在各种开发方式中,设计都是非常重要的一个环节,它在很大程度上影响了软件开发的难度、质量。
在传统的软件设计方法中,需求分析的结果通常以文档、UML图、伪代码等方式表示出来。
在TDD中,一般可以使用测试用例来表示各个模块的功能说明。
测试用例可以明确地表示每个功能模块要完成的功能和期望得到的结果,且不容易产生误解。
设计单元测试用例时,一个比较难以把握的问题是测试用例的粒度。
如果粒度太粗,可能会导致模块内实现的功能过多、难以测试等问题,并没有达到TDD 的效果。
TDD一般提倡小步前进。
但也不能太细。
粒度太细可能导致测试用例数量过多、维护测试用例过于麻烦。
2.1.2 创建测试用例
设计完测试用例以后,要实现测试用例。
测试用例将保证功能代码完成了设计的功能。
在没有写功能代码前,测试用例应该是无法通过的,因为需要完成的功能没有完成。
测试用例还在一定程度上起到了文档的作用。
在TDD的开发方式中,测试用例可以说明某个功能模块要完成的功能和它具有的接口。
测试用例对于功能代码的测试相当于黑盒测试,不用了解模块内部的实现,只管它是否满足需求。
对于模块内部要完成的功能,一般不写测试用例。
如要进行模块内部的测试可以通过开发工具的调试功能来完成。
测试用例主要测试模块的功能。
2.1.3 编写功能代码
TDD的通常做法是测试代码未编写完成前是不写功能代码的,并且测试代码写完后是无法通过测试的。
此时需要编写功能代码通过测试代码。
值得注意的是,功能代码并不是越复杂越完善越好。
最好的做法是所写的功能代码刚好通过所有测试用例。
编写完代码后要运行所有测试用例并保证全部通过。
如果没有全部通过,就要对代码进行修改,直到通过所有测试。
不应该在测试没有全部通过的情况下去编写其它代码。
2.1.4 重构
常有人质疑TDD开发方式所开发的软件质量。
由于TDD在编写功能代码时只注重于快速完成代码并通过所有测试,并没有对代码的质量进行检验,所以这里面的代码质量无法得到保证。
这样的质疑并不是没有道理。
但是TDD的开发方式中也有比较重要的一个环节,重构。
在面向对象的开发方式中,几乎都会比较重视重构。
它能提高代码的质量,利于以后对代码的修改和维护。
采用TDD的开发方式也应该有重构。
重构不应该修改与外部的接口而应该重点优化内部实现的代码。
TDD有测试来验证重构后的代码不会影响外部接口。
在进行代码修改以后,要重新运行所有测试,并保证全部通过。
重构不是一次就能完成的,可能会多次进行,并在以后对项目进行修改的时候进行。
这一步常被很多开发者忽略,因为重构不增加新的功能,在运行时可能不会有明显的感觉。
但对于提高代码质量非常有帮助。
无论是否使用TDD都应该重视重构。
2.1.5 交付和部署
当程序代码编写完成,并通过各种测试以后,软件已经完成了客户需要的功能。
由于TDD在开发过程中用测试用例代替了部分需求说明文档和规格文档,省去了前期需求变化的过程中修改文档的麻烦。
在交付时可能需要补齐文档。
今后如果需要对软件进行修改,也只需要重复上述步骤。
但也要保证所写的代码尽量简单,测试覆盖率要高,功能代码需要通过全部测试。
2.2 应对需求变化
敏捷软件开发是要能够快速应对需求变化的。
TDD作为极限编程中倡导的软件开发方法也应该能够快速应对需求变化。
除了敏捷软件开发中要求的开发人员互相信任、经常面对面讨论等要求可以快速响应需求变化外。
当使用TDD时,如果需求发生变化,则要设计和修改测试代码以反应需求的变化。
当测试代码改变后,可以根据运行测试后的结果快速的发现哪些模块需要更改。
只要修改代码使测试通过就可以了,而不用担心是不是又有其它地方出现了bug。
TDD一个很大的好处也就是开发人员有明确的目标,代码可以马上进行测试并保证完成想要达到的功能,并通过测试覆盖率了解到是否有多余的代码。
2.3 工具
2.3.1 JUnit
JUnit是一个开源的测试框架,主要是用来对Java程序进行自动化单元测试的[4]。
它能很好地集成在Eclipse中对代码进行测试。
它的主要功能有对测试结果断言、共享测试数据、运行测试。
JUnit是xUnit中的一个,其它类似的还有NUnit用于测试.NET代码,CppUnit 测试C++代码。
2.3.2 EasyMock
EasyMock是一个开源的生成Mock对象的工具,可以隔离测试对象与其它辅助的对象。
它可以模拟出一个对象并记录它期望进行的行为和结果。
在回放状态调用它以进行测试。
还可以对Mock的对象进行验证。
3 结束语
本文介绍了测试驱动开发的一些特点和实现过程,并介绍了相关工具。
通过与持续集成等其它敏捷软件开发工具和技术结合,可以较好地应对需求变化、及时发现问题并保证软件质量。
参考文献
[1]陈立群.测试驱动开发在J2EE项目中的全程实践[J].计算机工程与科学,2008,30(4):86-88.
[2]侯典荟.基于.NET环境测试驱动开发研究与应用[D].大连理工大学,2006.
[3]Janzen D S,Saiedian H. On the influence of test-driven development on software design[C]. Turtle Bay,HI,United states:Institute of Electrical and Electronics Engineers Inc,2006.
[4]白凯,崔冬华.基于JUnit自动化单元测试的研究[J].计算机与数字工程,2010,38(2):52-54,103.。