当前位置:文档之家› JUnit设计模式分析

JUnit设计模式分析

JUnit设计模式分析JUnit是一个优秀的Java单元测试框架,由两位世界级软件大师Erich Gamma 和Kent Beck共同开发完成。

本文将向读者介绍在开发JUnit的过程中是怎样应用设计模式的。

关键词:单元测试JUnit 设计模式1 JUnit概述1.1 JUnit概述JUnit是一个开源的java测试框架,它是Xuint测试体系架构的一种实现。

在JUnit单元测试框架的设计时,设定了三个总体目标,第一个是简化测试的编写,这种简化包括测试框架的学习和实际测试单元的编写;第二个是使测试单元保持持久性;第三个则是可以利用既有的测试来编写相关的测试。

所以这些目的也为什么使用模式的根本原因。

1.2 JUnit开发者JUnit最初由Erich Gamma 和Kent Beck所开发。

Erich Gamma博士是瑞士苏伊士国际面向对象技术软件中心的技术主管,也是巨著《设计模式》的四作者之一。

Kent Beck先生是XP(Extreme Programmin g)的创始人,他倡导软件开发的模式定义,CRC卡片在软件开发过程中的使用,HotDraw软件的体系结构,基于xUnit的测试框架,重新评估了在软件开发过程中测试优先的编程模式。

是《The Smalltalk Best Practice Patterns》、《Extreme Programming Explained》和《Planning Extreme Programming(与Martin Fowler合著)》的作者。

由于JUnit是两位世界级大师的作品,所以值得大家细细品味,现在就把JUnit中使用的设计模式总结出来与大家分享。

我按照问题的提出,模式的选择,具体实现,使用效果这种过程展示如何将模式应用于JUnit。

2 JUnit体系架构JUnit的设计使用以Patterns Generate Architectures(请参见Patterns Generate Architectures, Kent Beck and Ralph Johnson, ECOOP 94)的方式来架构系统。

其设计思想是通过从零开始来应用设计模式,然后一个接一个,直至你获得最终合适的系统架构。

3 JUnit设计模式3.1 JUnit框架组成l 对测试目标进行测试的方法与过程集合,可将其称为测试用例。

(TestCase)l 测试用例的集合,可容纳多个测试用例(TestCase),将其称作测试包。

(TestSuite)l 测试结果的描述与记录。

(TestResult)l 测试过程中的事件监听者(TestListener)l 每一个测试方法所发生的与预期不一致状况的描述,称其测试失败元素。

(TestFailure)l JUnit Framework中的出错异常。

(AssertionFailedError)3.2 Command(命令)模式3.2.1 问题首先要明白,JUnit是一个测试framework,测试人员只需开发测试用例。

然后把这些测试用例组成请求(有时可能是一个或者多个),发送到JUnit FrameWork,然后由JUnit执行测试,最后报告详细测试结果。

其中包括执行的时间,错误方法,错误位置等。

这样测试用例的开发人员就不需知道JUnit内部的细节,只要符合它定义的请求格式即可。

从JUnit的角度考虑,它并不需要知道请求TestCase的操作信息,仅把它当作一种命令来执行,然后把执行测试结果发给测试人员。

这样就使JUnit 框架和TestCase的开发人员独立开来,使得请求的一方不必知道接收请求一方的详细信息,更不必知道是怎样被接收,以及怎样被执行的,实现系统的松耦合。

3.2.2 模式的选择Command(命令)模式(请参见Gamma, E., et al. Design Patterns: Elements of Reusable Object-Oriented Software, Addison-Wesley, Reading, MA, 1995)则能够比较好地满足需求。

摘引其意图(intent),将一个请求封装成一个对象,从而使你可用不同的请求对客户进行参数化;对请求进行排队或记录请求日志mand告诉我们可以为一个操作生成一个对象并给出它的一个execute(执行)方法。

3.2.3 实现为了实现Command模式,首先定义了一个接口Test,其中Run便是Command的Execute方法。

然后又使用Default Adapter模式为这个接口提供了缺省实现TestCase抽象类,这样我们开发人员就可以从这个缺省实现进行集成,而不必从Test接口进行实现。

我们首先来分析Test接口。

它存在一个是countTestCases方法,它来统计这次测试有多少个TestCase,另外一个方法就是我们的Command模式的Excecute方法,这里命名为run。

还有一个参数TestResult,它来统计测试结果public interface Test {/*** Counts the number of test cases that will be run by this test.*/public abstract int countTestCases();/*** Runs a test and collects its result in a TestResult instance.*/public abstract void run(TestResult result);}TestCase是该接口的抽象实现,它增加了一个测试名称,因为每一个TestCase在创建时都要有一个名称,因此若一个测试失败了,你便可识别出是哪个测试失败。

public abstract class TestCase extends Assert implements Test {/*** the name of the test case*/private String fName;public void run(TestResult result) {result.run(this);}}这样我们的开发人员,编写测试用例时,只需继承TestCase,来完成run方法即可,然后JUnit获得测试用例,执行它的run方法,把测试结果记录在TestResult之中,目前可以暂且这样理解。

3.2.4 效果下面来考虑经过使用Command模式后给系统的架构带来了那些效果:l Command模式将实现请求的一方(TestCase开发)和调用一方(JUnit Fromwork)进行解藕l Command模式使新的TestCase很容易的加入,无需改变已有的类,只需继承TestCase类即可,这样方便了测试人员l Command模式可以将多个TestCase进行组合成一个复合命令,实际你将看到TestSuit就是它的复合命令,当然它使用了Composite模式l Command模式容易把请求的TestCase组合成请求队列,这样使接收请求的一方(Junit Fromwork),容易的决定是否执行请求,或者一旦发现测试用例失败或者错误可以立刻停止进行报告l Command模式可以在需要的情况下,方便的实现对请求的Undo和Redo,以及记录Log,这部分目前在JUnit中还没有实现,将来是很容易加入的3.3 Composite(组合)3.3.1 问题为了获得对系统状态的信心,需要运行多个测试用例。

通过我们使用Command模式,JUnit能够方便的运行一个单独的测试案例之后产生测试结果。

可是在实际的测试过程中,需要把多个测试用例进行组合成为一个复合的测试用例,当作一个请求发送给JUnit.这样JUnit就为面临一个问题,必须考虑测试请求的类型,是一个单一的TestCase还是一个复合的TestCase,甚至于要区分到底有多少个TestCase。

这样Junit 框架就要完成像下面这样的代码:if(isSingleTestCase(objectRequest)){//如果是单个的TestCase,执行run,获得测试结果objectRequest.run()}else if(isCompositeTestCase(objectRequest)){//如果是一个复合TestCase,就要执行不同的操作,然后进行复杂的算法进行分//解,之后再运行每一个TestCase,最后获得测试结果,同时又要考虑//如果中间测试错误怎样????、……………………………………………………}这样JUnit必须考虑区分请求(TestCase)的类型(是单个testCase还是复合testCase),而实际上大多数情况下,测试人员认为这两者是一样的。

对于这两者的区别使用,又会使程序变得更加复杂,难以维护和扩展。

于是要考虑,怎样设计JUnit才可以实现不需要区分单个TestCase还是复合TestCase,把它们统一成相同的请求?3.3.2 模式的选择当测试调用者不必关心其运行的是一个或多个测试案例的请求时,能够轻松地解决这个问题模式就是Composite(组合)模式。

摘引其意图,将对象组合成树形结构以表示部分-整体的层次结构。

Composite使得用户对单个对象和组合对象的使用具有一致性。

在这里部分-整体的层次结构是解决问题的关键,可以把单个的TestCase看作部分,而把复合的TestCase(TestSuit)看作整体。

这样我们使用该模式便可以恰到好处得解决这个难题。

Composite模式结构Composite模式引入以下的参与者:n Component:这是一个抽象角色,它给参加组合的对象规定一个接口。

这个角色,给出共有的接口和默认得行为。

其实就我们的Test接口,它定义出run方法。

n Composite:实现共有接口并维护一个测试的集合。

就是我们的复合TestCase,TestSuitn Leaf:代表参加组合的对象,它没有下级子对象,仅定义出参加组合的原始对象的行为,其实就是单一的测试用例TestCase,它仅实现Test接口的方法。

其实componsite模式根据所实现的接口区分为两种形式,分别称为安全式和透明式。

JUnit中使用了安全式的结构,这样在TestCase中没有管理子对象的方法。

3.3.3 实现composite模式告诉我们要引入一个Component抽象类,为Leaf对象和composite对象定义公共的接口。

这个类的基本意图就是定义一个接口。

在Java中使用Composite模式时,优先考虑使用接口,而非抽象类,因此引入一个Test接口。

相关主题