测试驱动开发
测试驱动开发
概述
极限编程是一个轻量级的、灵巧的软件开发方法,同时它也是一个非常严
谨和周密的方法,它从 4 个基本方面对软件项目进行改善:交流、简易、反馈
和勇气。测试驱动开发则是极限编程的最佳实践之一。它是编程时使用的技术,
要求在编写任何产品代码之前,首先编写用于定义产品代码行为的测试。采用
测试驱动开发,我们将得到简单、清晰、高质量的代码。 MVC 模式是一个复杂的架构模式,它将一个应用的输入、处理、输出流程按照 Model、View、Controller 的方式进行分离,使得产品的结构清晰,易于 维护,有利于软件工程化管理。 Kent Beck 作为极限编程的创始人,提出了测试驱动开发的部分方法,并成功地应用于许多小型的项目中。但是,测试驱动开发在许多系统中应用还存在一定的难度,比如具有图形用户界面和多层架构的系统。所以,基于设计模式的测试驱动开发的研究成为国内外软件工程方向研究者们的课题之一。
反馈是 XP 的四个基本的价值观之一——在软件开发中,只有通过充分的测试才能获得充分的反馈。XP 中提出的测试,在其它软件开发方法中都可以见到,比如功能测试、单元测试、系统测试和负荷测试等;与众不同的是,XP 将测试结合到它独特的螺旋式增量型开发过程中,测试随着项目的进展而不断积累。另外,由于强调整个开发小组拥有代码,测试也是由大家共同维护的。即,任何人在往代码库中放程序前,都应该运行一遍所有的测试;任何人如果发现了一个 BUG,都应该立即为这个 BUG 增加一个测试,而不是等待写那个程序的人来完成;任何人接手其他人的任务,或者修改其他人的代码和设计,改动完以后如果能通过所有测试,就证明他的工作没有破坏原系统。这样,测试才能真正起到帮助获得反馈的作用;而且,通过不断地优先编写和累积,测试应该可以基本覆盖全部的客户和开发需求,因此开发人员和客户可以得到尽可能充足的反馈。
测试驱动开发(Test- Driven Development), 简称TDD, 由Kent Beck 提出的一种软件开发方式。测试驱动开发以测试作为开发过程的中心, 它要求在编写任何产品代码之前, 首先编写用于定义产品代码行为的测试, 而编写的产品代码又要以使测试通过为目标。测试驱动开发要求测试可以完全自动化的运行, 在对代码进行重构前后必须运行测试。测试驱动开发主要包括两方面:测试先行和代码重构。测试主要针对单元(最小的可测试软件元素)实施测试。它所测试的内容包括内部结构(如逻辑和数据流)以及单元的功能和可观测的行为。测试先行一改传统开发模式的单元测试在编写代码之后进行, 而将单元测试的编写移至编写正式代码之前。重构是在不改变代码外在行为的条件下改进其内部的行为的一种软件系统改变的过程, 使代码松耦合度(对外界代码依赖低)并且内聚度高(内部只完成一项功能) 。测试驱动开发作为极限 编程思想的一种主要实践, 可以有效地让程序开发人员开发出更高品质的、经过完整测试的程序。测试驱动开发以测试作为开发过程的开端, 它要求在编写任何产品代码之前,首先编写用于定义产品代码行为的测试, 而编写的产品代码又要以使测试通过为目标。TDD 不是一种开发工具,也不是一种测试方法, 它是一种编码之前进行单元测试的软件开发思想。
-
测试驱动开发的研究与实践
测试驱动开发流程:TDD 开发过程有别于传统开发流程(Waterfall), 它在进行简单的概要设计后, 首先进行的是测试用例的编写,然后执行测试用例进行测试。测试失败, 则进行编码驱使测试通过, 这就是所谓的测试驱动。最终, 测试得到通过,再对代码进行重构,优化代码结构和性能。而传统流程则先进行概要设计, 然后在概要设计基础上进行详细设计,在详细设计阶段尽可能设想到全部问题和需求的解决方法, 然后才开始编码实现详细设计。TDD 开发流程图如图所示。
测试驱动开发模式:在测试驱动开发中,关键问题如下:什么时候进行测试,如何选择要测试的逻辑和如何选择要测试的数据。测试驱动开发模式指导程序员如何解决上述问题。
*测试相互独立。
在测试驱动开发中, 所运行的各种测试之间关系的期望状态是没有任何相互影响的。相互独立的测试意味着所有的测试都是不依赖于顺序的, 可以随便从这些测试中挑出部分测试来运行。程序员必须将自己的问题分解为一些彼此正交的小问题, 这样就使得为每个测试搭建环境
简单而快捷。独立测试鼓励利用高度内聚、低度耦合的对象组合来解决问题。
*写出测试列表。
程序员在开始写测试之前, 应该写一个包含所有必须要编写的测试的清单。那么, 记录到列表上的就是当前程序员要去实现的测试。首先将需要实现的每种操作的范例都记录在清单上。对于目前尚不存在的操作, 将其空版本记录在清单上。
*测试和断言优先。
在测试驱动开发中, 程序员构建一个系统应该是从其对最终系统的描述开始的。程序员应该从希望最终代码能够通过的测试开始编写一项功能。相应地,程序员应该从测试完成时能够通过的断言开始编写一个测试。在测试优先的测试里程序员应该尽量使用容易让人理解的数据, 一般不用一个常量来表达多种意思。
一般从测试列表中选择具有指导意义并且比较有把握实现的测试来进行编写。当使用一个新类里的一种新的方法时, 不直接用它来编写程序, 而是编写一个小测试来验证这个API 的工作是否符合人们的愿望。当出现某种与当前讨论话题并不直接相关的想法时, 那么就在列表中增加一个测试然后重新回到论题上来。当发现一个错误的时候, 首先写一个尽可能小的测试并使其运行, 然后再去修复这个错误。
利用JUnit进行测试驱动开发:在Eclipse 建立JUnit 测试, 并进行驱动开发。现在开 发一个"Hello Wor ld" 的例子。按照TDD 的规则, 应该在代码建立以前先把测试写好。为了能够在某处开始, 假设未来的类名是HelloWorld , 并且有一个方法Say(), 这个方法返回String 的值(例如"Hello World !")。根据设定的程序功能, 写出测试代码如下:
import junit .framework.T estCase ;
public class TestThatWeGetHelloWorldPrompt
extends TestCase {
public TestThatWeGetHelloWorldPrompt(
String name){
super(name);
}
public void testSay(){
HelloWorld hi=new HelloWorld();
assertEquals(" Hello World!" , hi.say());
}
public static void main(String[ ] args){
junit.textui.TestRunner.run(
TestThatWeGetHelloWorldPrompt.class);
}
}
建立测试案例的步骤如下:
1)建立一个junit.framework.TestCase的实例。
2)定义一些以"test" 开头的无返回方法(例如test-WasTransactionSuccessful(), testS how(), 等等)。
TestThatWeGetHelloWorldPrompt .java 包含这些:TestCase 的子类和一个叫做testSay()的方法。这个方法调用了assertEquals()函数, 它用来比较预期的值和由say()返回的值。main()方法用来运行测试和显示输出。JUnit 的TestRunner 处理测试, 提供基于图像和文本的输出表现形式。我们使用基于文本的版本, 因为Eclipse 支持它, 且也适合我们。当开始运行后, 基于文本的版本测试会以文本形式输出,Eclipse 会把这些输出自动变成图像界面的输出。
现在建立被测试代码:
public class HelloWorld {
public String say(){
return("Hello World!");
}
}
-
测试驱动开发在Java语言中的运用
测试驱动开发与Java结合的实践应用:很多同学在程序开发过程中对测试不够重视,主要表现为:第一,没有针对实际问题设立出足够全面的测试用例;第二,主管认为某些代码是正确的,实际上无法为这些代码设计相应的测试用例。将测试驱动开发与Java课程有机结合起来,能够有效地客服同学们对测试认识的不足,从而编写出更高质量的程序。经过实践,可遵循以下步骤:
首先编写测试用例:测试用例是对实际需求的现。用户向程序输入一个测试用例,则期望程序给出某些输出。输入和输出往往表现为函数关系。在传统的编程方式中,程序员也会考虑到实际需求问题,但往往由于仅限于思维上的没有做出清晰归纳的印象。尤其是一些心急的程序员,觉得写代码就是解决问题的全部工程。实际上这样忽略测试用例而编写出来的程序很容易未能覆盖实际问题的各方面要求。
编写仅能通过测试用的代码:在编写测试用例阶段,首先要遵循的是:让编译器告知程序员,合适该增加新的方法,而不是主动对程序做出规划。在实际的Java语言课程教学实践中发现,有许多同学在针对某测试用例编写通过代码时,喜欢即兴发挥,写出一些并非通过本测试用例所需要的代码。这样可能会导致几个方面的问题:第一,这些代码无合适的测试用例验证,可能永远都不会被执行;第二,这些代码存在错误,但由于当前测试用例不是用于检验这些代码的,它们可能会遗漏到后期的软件开发中,甚至被集成到其它软件,造成后期难以检测出来的隐患;第三,这些代码可以解决问题的某一方面,但放置位置不合适,造成代
码意义模糊。例如在上面的代码中,有些同学在完成了当前测试用例后,马上想到对于以文本文件方式输入的同类型的数据也可以使用同样的程序代码处理,于是在方法中加入有关文本文件的代码,这样的做法其实不合适,因为有关文本文件方式输入的处理应该在求最大公约数之前的方法中实现。
代码重构:代码重构对于测试驱动开发来说相当重要。当程序中代码的代码越来越多,就有可能需要进行重构,以优化程序性能,并使程序更加"优美"。例如代码出现重复、某些代码要表达的意图过于复杂时,程序员都要考虑进行重构的必要性。代码重构与代码编写是交错进行的。代码编写是进行代码重构的基础,而适时地进行代码重构将能极大地加快代码编写的进度。另一方面,代码重构无可避免地增加了代码编写阶段的工作量,所以在进行重构的时机和范围都需要根据实际问题
维护程序员测试集。进行增量式开发:对于测试集的编写,则应当遵循"不遗漏,不重复"的原则。通过前三个步骤,不断扩充测试用例至测试集,并立刻针对扩充的测试用例编写能通过的代码,直至测试集包括了实际问题的所有方面为止,则认为程序开发的代码编写阶段已经完成。
-
测试驱动开发在J2EE项目中实践
J2EE是一种用来开发企业级软件应用系统的平台。目前针对J2EE项目,多采用多层架构设计,清晰简单、分工合作,每层使用特定的框架实现相应的设计策略。比如,Strum+Sprig+Hibernate就是一个很受欢迎的开源整合框架:表示层用Struts实现,业务层用Spring实现,持久层则用Hibernate实现。
在这个整合框架下进行开发,对于普通水准的J2EE开发者来说,可能会有太多的时间被浪费在非关键任务上,或者是仅仅为了执行单元测试就不得不把所有程序部署到应用服务器上,其生产率是无法令人满意的。于是,一种全新的软件开发方法(测试驱动开发)就被提出且日益流行起来。
JUnit工具介绍:作为流行成熟的回归测试框架,JUIlit提供了基于API的自动测试方法,您可以在测试代码中调用这个框架来检查条件是否满足,并报告错误的数量和类型。这种方案非常灵活,大多数情况下它大大减少了测试代码的维护时间,并且使应用中的复杂功能测试成为可能,还可交替使用白盒测试或黑盒测试。。本文所讨论的测试工具有JMock、SpringContextTestCase、StrutsTestCase、Canoo WebTest,也都是JUnit在具体领域的扩展。
项目组织结构:本项目采用的分层架构使Web应用达到了松散耦合还能灵活改变,并可以承载各种级别的业务处理,每层之间开放通信接口。各层都采用了测试先行编程的开发方法。
src/dao(数据访问对象)目录存放持久层和域模型的实现;src/service目录存放业务层的实现;src/web目录存放表示层的实现。每层的测试用例则相应地存放在test目录下。
Member类有四个属性,部分代码如下:
持久层测试:
该层测试使用了Spring对JUnit的扩展测试框架,AbstractTransactionalDataSourceSpringContextTests类的继承类MemberDaoTest可以不必依赖服务器而直接运行,从而对集成测试(类似单元测试)提供了良好的支持可以随意更新表中的数据而不必担心造成影响,因Spring的测试类支持事务管理,会自动圆滚在测试中所做的任何修改。按照TDD的骤接下来才是编写程序代码 ,创建MemberDao接口和相应的实现类MemberDao
-Hibernate,然后在Spring配置文件中绑定。现在可以直接在Junit中进行测试。若测试通过,转到业务层开发。
业务层测试: 我们使用的测试工具是JMock,它可以灵活地定义对象间交互时的约束关系,减少测试的脆弱性。
使用JMock,需要继承MockObjeetTestCase类,先建立测试运行的上下文,然后设定Mock对象使用到方法、参数、返回值等行为,最后执行测试。按照测试先行方法,现在应该声明MemberManager接口并实现MemberManagerImpl类。
表示层测试:Struts框架基于MVC(模型一视图一控制)设计模式,将数据访问、页面显示、流程逻辑三部分分离开来。这使得Web应用的容器内功能测试和单元测试变得困难。StrutsTestCase正是为测试Struts Web应用而创建的Mock测试框架,它无需启动Servlet容器就可以方便地测试.接下来,是创建MemberAction类、MemberForm类、memberForm页和memberList页的时候;然后开始该层测试。
-
在设计模式中的应用
在传统的软件工程中,软件开发过程讲究的是前期详尽的需求和系统详细设计,以便开发出软件系统尽量与实际一致,但是这样做有一个缺点,容易造成 " 设计过度"。所谓设计过度,就是在尚未完全理解客户需求的基础上,就根据自己的理解做详细设计,并力求把系统设计得完美灵活。 然而一旦客户不需要那些功能或是改变需求的话, 就会造成开发过程中极大的浪费。
测试驱动开发 ( test-driven development,TDD)是一种新型的程序开发方式,而不是一种测试方法,它是由 Kent Beck、Devid Astels 等人提出的,与传统的程序设计方法不同的软件开发方式,其基本思想是首先编写测试代码, 由测试来决定要编写哪些程序代码。TDD 的缺点是在前期过少的考虑整个系统架构,过多的强调了先测试后编码的原则,导致后面增加了重构的难度。
设计模式[4]是在软件设计过程中解决某一类问题的方法。设计模式的基本思想是:根据系统的需求,在经过前人总结得出的方法中选出一种最适合当前系统使用的方法。 使用设计模式的好处是, 它是在无数前人经验的基础上总结得出的一些最本质的设计方法, 使用设计模式可以缩短系统结构设计的时间,能够保证系统的健壮性、扩展性和可维护性。 因此,设计模式是一种指导,在它的指导下,不仅有助于完成任务,而且有助于得到解决问题的最佳办法,从而做出一个优良的设计方案以达到事半功倍的效果。
为了弥补TDD前期开发对系统结构设计不足的缺点,将TDD与设计模式结合进行软件设计则是一种新型开发方法。
TDD的基本步骤如下:
步骤 1 先写一段单元测试代码;
步骤 2 执行这个测试代码,不能通过编译;
步骤 3 写所能想到的最简单的程序代码,让单元测试代码可以通过编译;
步骤 4 再次执行这个单元测试,应该会得到验证失败的结果 ( 如果通过的话,说明单元测试没有击中要害,需要修改测试代码);
步骤 5 写主程序,让单元测试可以顺利通过验证;
步骤 6 回到步骤 1,开始写新的单元测试。
软件工程中无数项目的成功经验证明, 设计模式是非常重要和必要的。 对于初步接触
TDD 的编程人员来说,结合设计模式进行的测试驱动开发最合理的方式应该是:① 花一定的时间做好前期的分析,在研究模式上投入时间;② 在最初以最简单的形式实现模式,以后再增加其复杂性;③ 如果使用了一种模式,而在以后发现无法满足需要时,通过转换的方式将其修改。 使用了结合设计模式进行的 TDD,将会极大的减少修改构架的复杂度,使得修改朝着有序的方向进行。
结合设计模式的TDD的开发流程基本如下:
可以看到,设计模式主要是用于业务逻辑层中。 业务逻辑层的作用就是处理系统中的各个业务逻辑,并将所得结果通过接口提供给外部的展现层调用。在开发过程中,遇到需要系统构架调整的时候,只要保持对应用程序的展示层的接口方法不变,无论下面层次中的程序做如何大的改动,前台都不需要做相应的变动,实现了展示层同业务逻辑层相分离的原则。这就是在 TDD 中也要使用设计模式的好处。
-
基于MVC的测试驱动开发
基于 MVC 架构的测试驱动开发过程:由于具有使 View、Controller 与 Model 分离开来的特性,MVC 很适用于 GUI 软件的开发。目前许多 GUI 软件的结构都是基于或者是部分地基于MVC 的。比如,Microsoft Foundation Class(MFC)-----它把 View 和 Controller 集成在视图内,文档负责数据的表示以及存取(Model) ,视图负责显示文档内容(View)以及处理用户界面上的操作( Controller);Struts-----它采用EJB 作为模型,JSP 和 Custom Tag Library 配合作为View,Servlet作为控制器。
根据对 MVC 架构各层的特点的分析,三层中 Controller 反映了应用程序的功能和流程,并且清楚 Model 和 View 的功能,所以测试驱动开发应该从Controller 出发,首先将开发的重点放在实现程序的功能上,更早地实现需求。由于在 Controller 的开发过程中需要不断地对 Model 和 View 进行重构,为了减少重构的代价,可以将 Model 中未实现的对象用 Mock Object 来代替。当在实现一个用户故事的 Controller 后,或者实现多个 Controller 后,从 Controller 层可以提取出 View 与 Controller 之间数据传递的信息,根据这些信息可以进行View 层的设计和开发,View 的实现主要考虑以怎样的视图来显示这些信息,以及设计怎样的事件来触发Controller中相应的方法。另一方面,当Controller 中可以至少提取出一个完整的 Model 对象时,调用 Model 层代码生成工具生成Model 的程序代码和测试代码。
测试驱动开发中 MVC架构各部分的关系:MVC 架构的形式化分析,可知 MVC 三层模块之间是相互依赖的关系,而三层中 Controller 层反映了程序的控制逻辑,它的实现依赖于 Model向数据库获取数据,又依赖于 View 将更新的数据显示在界面上。所以在测试驱动开发 Controller 过程中可以设计出 Model 和 View 的接口。View 只是用开发环境提供的各种控件将数据简单的显示在界面上。Model 主要是对数据进行处理,数据处理的过程有其规律性,在绝大部分系统中,这些对象的方法主要是对数据库的操作,包括增加、删除、查询、修改等。三者的对应关系如下图。测试代码传入测试数据对被测代码的 public方法进行测试,随着 Controller 功能的实现,在 Controller 的程序代码部分可以知道,Model 和 View 对象的接口信息逐渐被设计和编写出来。对于 View 来说,它只负责显示图形用户界面,不涉及任何的功能代码,所以 View 层不适合作测试驱动开发,而是将 View 的测试集中在用户界面风格上,比如用户界面的一致性、界面的布局、用户界面之间的切换是否顺畅、颜色的使用是否适当、以及界面的设计是否考虑不同用户的需求等等。在 Web 界面测试方面,配合使用ASPUnit 和 HttpUnit 等自动化测试工具可以提高测试效率。Model 的测试集中在每个对象的方法是否返回正确的结果,Model 的方法确定了,对方法的测试用例也可以确定下来,而测试数据可以从 Controller 测试代码中用于测试的数据中获得。为了提供程序的编写效率,可以先从 Controller 的测试代码和程序代码提取出生成 Model 代码所需的信息,再利用代码生成工具,生成 Model 的测试代码和程序代码。
Model信息的提取
对测试驱动开发 Controller的基本约定
对 Controller 的开发基本按照测试驱动开发的步骤来进行,将开发的重点放在实现程序的功能上。但是,为了能更好的实现从 Controller 层抽取出 Model和 View 层信息,并保证 Controller 层的可测试性,在开发 Controller 层时,还应该做到以下几点:
1. 保持 View 的简单性,将事件代码交给 Controller 处理。因为测试 View是困难和繁琐的, 所以View应该是尽可能的简单。View中各控件的event handle事件只是传递的作用,具体的功能较由 Controller 的方法处理。
2. MVC 三层的通信都要经过 Controller 层。这种限制保证了 Model 和 View 的分离,同时也保证了 Controller 层的测试用例可以完全覆盖整个程序的功能。
3.为了便于用程序实现在 Controller 中提取自动生成 Model 的信息,Controller 代码中的某些方法和属性的命名应遵循一定的规则,具体如下:
1) Model 方法的命名:方法类型+Model 类名,如 InsertUser。
2) Model 几个常用方法的类型为:Insert 表示"插入",Search 表示"查询",Get 表示"单个查询",Update 表示"更新",Delete 表示"删除"。
3)Controller 测试程序中的一个测试类对应一个 Controller 类,一个测试方法对应一个 Controller 方法的一个测试用例。
-
嵌入式系统测试驱动开发的策略
双目标开发策略:对多数嵌入式项目来讲,并行进行硬件和软件开发是个现实。如果只能在目标硬件上运行,有可能会有多个浪费时间的因素。但并不是所有的开发团队都会遇到浪费时间的问题,传统意义上,这也是嵌入式开发者会转而使用评估板来缓解目标硬件的一个原因。评估板是在开发时使用的一种电路板,它有同目标系统相同的处理器配置,理想情况下还有同样的输入输出接口。评估板能保护不会延迟项目,但是这还不够,评估板仍然有构建时间长的问题。双目标开发则是解决上述瓶颈问题的一个策略。双目标是指代码被设计成至少应能在两个平台上运行:代码最终是要在一个嵌入式目标硬件上运行,但它首先在开发系统中写出和测试的,而双目标解决了以下几个问题:它可以在硬件就绪之前就测试代码,并使它在整个软件开发周期里避免硬件带来的瓶颈,还可避免随硬件和软件同时调试带来的互相指责。双目标还会影响设计、对软件与硬件之间边界的关注会产生更模块化的设计。在开发系统中,测试代码会在把代码应用于目标硬件之前来帮助开发人员建立信心,但在双目标方案当中存在其固有的风险。所以这些可能导致在一个环境里运行没有错误的代码却在另一个环境里却测试失败。在嵌入式中的TDD循环可以较好地应对这些问题。
嵌入式的TDD循环:嵌入式的TDD循环是对TDD微循环的扩展,它可以克服目标硬件所带来的瓶颈。当构建和测试的循环只有几秒钟的情况下TDD效果最好,更长的构建和测试时间会导致采用更大的步伐。对这种快速反馈的需求迫使TDD的微循环脱离目标硬件,而运行在本地的开发系统中。TDD微循环是嵌人式TDD循环的第一个平台,如图所示。
平台2~4被设计用于缓解用开发平台来运行单元测试所带来的风险。平台5确保完整集成后的系统能够提供可工作的特性。
平台1:TDD微循环。在这个平台运行得最频繁,通常几分钟一次。大部分代码会在这个平台中写出,并且只在开发系统本地编译。测试是在开发系统里完成的,这样它能给出快速反馈,而不会被硬件的可靠性或可用性的约束拖累。在这个平台中,需要写于平台无关的代码。要寻找把软件和硬件断开的机会,硬件和软件的边界要很清楚,并记录在测试用例中。
平台2:编译器兼容性检查。要定期的为目标系统作编译,采用为产品而使用的交叉编译器。这个平台是对编译器不兼容的一个早期警告。它会警告移植问题,如头文件不可用,语言支持不兼容,以及语言特性缺失等,不必在每次代码改变时都运行平台2。在每次采用了新的语言特性时做一下目标系统的交叉编译。
平台3:在评估板上运行单元测试。有一个风险是,编译后的代码在本地开发系统和目标处理器上运行起来是不同的。为缓和这种风险,可以在评估板上运行单元测试。使用评估板可以看到代码在开发系统和目标处理器上行为的差异。拥有在评估板上运行的能力,即使在目标硬件就绪之后可能仍然比较方便。如果有一可疑的目标硬件行为,可以快速地通过在评估板上运行单元测试,以把目标硬件的问题包含进来或排出。
平台4:在目标硬件上运行单元测试。平台4的目的和平台3相同,只是平台4会使用真实的内存。而且可以运行只能在目标硬件上运行的测试。这些测试可以识别出或者学习到目标硬件的行为。这个平台一个新增的功能是目标硬件上有限的内存。在这种情况下,可以把测试组织成不同的测试套件,使每个套件都能装进内存中。
平台5:在目标硬件上运行验收测试。最后,需要在目标硬件上运行自动化的和手工的验收测试来保证产品特性。这里要确保任何不能完全被自动化测试的、依赖于硬件的代码都会被手工测试。
[1] Badreddin O, Forward A, Lethbridge T C. A test-driven approach for developing software languages[C]// International Conference on Model-Driven Engineering and Software Development. IEEE, 2014:225-234.
[2] 苏庆.SU Qing 测试驱动开发在Java语言课程实践中的应用[期刊论文]-广东工业大学学报(社会科学版) 2008(z1)
[3] 程烨.高建华.CHENG Ye.GAO Jian-hua与设计模式相结合的测试驱动开发方法[期刊论文]-计算机工程与设计 2006(16)
[4]Pipka J U. Test-Driven Web Application Development in Java[C]// Revised Papers from the International Conference NetObjectDays on Objects, Components, Architectures, Services, and Applications for a Networked World. Springer-Verlag, 2002:378-393.
[5] Kent Beck. Test-Driven Development—By Example[J]. Pearson Schweiz Ag, 2003.
[6] 黎利 基于MVC的测试驱动开发研究[学位论文]硕士 2007
[7] 陈立群.CHEN Li-qun 测试驱动开发在J2EE项目中的全程实践[期刊论文]-计算机工程与科学2008(4)
[8] 张扬.黄厚宽.ZHANG Yang.HUANG Hou-kuan 测试驱动开发及开发实践[期刊论文]-计算机技术与发展 2006(5)
[9] 齐山松.姬进.QI Shansong.JI Jin测试驱动的嵌入式开发与实践[期刊论文]-电子科技 2013(8)