0OAD项目研究总结 JUnit 0461080李寻 0461005朱帆 0461023何文俊 0461079夏勇杰 0461106张蔚婷
OOAD 项目研究总结 JUnit 0461080 李寻 0461005 朱帆 0461023 何文俊 0461079 夏勇杰 0461106 张蔚婷
目录 1. JUnit研究总结…. 11 JUnit简介(李寻) 111单元测试 1111单元测试的好处 1112单元测试的针对对象… 111.3单元测试工具和框架 1.12 JUnit优点和 JUnit单元测试编写原则 113 JUnit的特征 114 JUnit框架与组成 115 JUnit的安装和配置 12 JUnit架构分析(李寻) 121接口分析 12.2 JUnit架构 13 JUnit设计模式(夏勇杰) 131简介 132什么是 JUnit的目标呢? 133 JUnit的设计 777888 13.31由此开始一 Test case 1332空白填充-run() 1333结果报告一 TestResult 1334不愚蠢的子类一再论 Test case 1335不必关心一个或多个一 TestSuit 1336总结. 134结论 19 14 JUnit版本演化(朱帆) 15 JUnit测试(张蔚婷). 16 JUnit集成应用(何文俊) 161应用综述 162Jnit与 Eclipse集成 2.个人贡献总结 21李寻 211小组组长 2.1.2 JUnit初步探索 21.3 JUnit架构探索 22夏勇杰 23朱帆 231个人贡献 232个人感想 24何文俊 2.5张蔚婷
目录 1. JUnit 研究总结 .............................................................................................................................3 1.1 JUnit 简介(李寻).................................................................................................................3 1.1.1 单元测试.................................................................................................................3 1.1.1.1 单元测试的好处..........................................................................................3 1.1.1.2 单元测试的针对对象..................................................................................3 1.1.1.3 单元测试工具和框架..................................................................................3 1.1.2 JUnit 优点和 JUnit 单元测试编写原则...................................................................3 1.1.3 JUnit 的特征 ............................................................................................................4 1.1.4 JUnit 框架与组成.....................................................................................................4 1.1.5 JUnit 的安装和配置.................................................................................................4 1.2 JUnit 架构分析(李寻).........................................................................................................5 1.2.1 接口分析.................................................................................................................5 1.2.2 JUnit 架构 ................................................................................................................7 1.3 JUnit 设计模式(夏勇杰) .....................................................................................................7 1.3.1 简介.........................................................................................................................7 1.3.2 什么是 JUnit 的目标呢? ......................................................................................8 1.3.3 JUnit 的设计 ............................................................................................................8 1.3.3.1 由此开始-TestCase.................................................................................8 1.3.3.2 空白填充-run()....................................................................................10 1.3.3.3 结果报告-TestResult ...........................................................................11 1.3.3.4 不愚蠢的子类-再论 TestCase..............................................................14 1.3.3.5 不必关心一个或多个-TestSuit ...........................................................15 1.3.3.6 总结........................................................................................................17 1.3.4 结论.................................................................................................................19 1.4 JUnit 版本演化(朱帆).......................................................................................................20 1.5 JUnit 测试(张蔚婷)...........................................................................................................21 1.6 JUnit 集成应用(何文俊) ...................................................................................................24 1.6.1 应用综述...............................................................................................................24 1.6.2 JUnit 与 Eclipse 集成 .............................................................................................24 2. 个人贡献总结............................................................................................................................34 2.1 李寻 .................................................................................................................................34 2.1.1 小组组长...............................................................................................................34 2.1.2 JUnit 初步探索 ......................................................................................................35 2.1.3 JUnit 架构探索 ......................................................................................................35 2.2 夏勇杰..............................................................................................................................35 2.3 朱帆 .................................................................................................................................35 2.3.1 个人贡献................................................................................................................35 2.3.2 个人感想...............................................................................................................36 2.4 何文俊..............................................................................................................................36 2.5 张蔚婷..............................................................................................................................36
1.儿Unt研究总结 11 JUnit简介 111单元测试 1111单元测试的好处 A、提高开发速度——测试是以自动化方式执行的,提升了测试代 码的执行效率。 B、提高软件代码质量—一它使用小版本发布至集成,便于实现人 员除错。同时引入重构概念,让代码更干净和富有弹性。 C、提升系统的可信赖度——它是回归测试的一种。支持修复或更 正后的“再测试”,可确保代码的正确性。 111.2单元测试的针对对象 A、面向过程的软件开发针对过程 B、面向对象的软件开发针对对象。 C、可以做类测试,功能测试,接口测试(最常用于测试类中的方 法) 1113单元测试工具和框架 目前的最流行的单元测试工具是 XUnit系列框架,常用的根据语言 不同分为儿Unt(java), CppUnit(C++), DUnit( Delphi),Nnit (net), PhpUnit(Php)等等。该测试框架的第一个和最杰出的 应用就是由 Erich gamma(《设计模式》的作者)和 Kent beck(XP ( Extreme Programming)的创始人)提供的开放源代码的 JUnit。 112 JUnit优点和 JUnit单元测试编写原则 优点: A、可以使测试代码与产品代码分开。 B、针对某一个类的测试代码通过较少的改动便可以应用于另一个 类的测试。 C、易于集成到测试人员的构建过程中,Jnit和Ant的结合可以实
1. JUnit 研究总结 1.1 JUnit 简介 1.1.1 单元测试 1.1.1.1 单元测试的好处 A、提高开发速度——测试是以自动化方式执行的,提升了测试代 码的执行效率。 B、提高软件代码质量——它使用小版本发布至集成,便于实现人 员除错。同时引入重构概念,让代码更干净和富有弹性。 C、提升系统的可信赖度——它是回归测试的一种。支持修复或更 正后的“再测试”,可确保代码的正确性。 1.1.1.2 单元测试的针对对象 A、面向过程的软件开发针对过程。 B、面向对象的软件开发针对对象。 C、可以做类测试,功能测试,接口测试(最常用于测试类中的方 法)。 1.1.1.3 单元测试工具和框架 目前的最流行的单元测试工具是 xUnit 系列框架,常用的根据语言 不同分为 JUnit(java),CppUnit(C++),DUnit (Delphi ),NUnit (.net),PhpUnit(Php )等等。该测试框架的第一个和最杰出的 应用就是由 Erich Gamma (《设计模式》的作者)和 Kent Beck(XP (Extreme Programming)的创始人 )提供的开放源代码的 JUnit。 1.1.2 JUnit 优点和 JUnit 单元测试编写原则 优点: A、可以使测试代码与产品代码分开。 B、针对某一个类的测试代码通过较少的改动便可以应用于另一个 类的测试。 C、易于集成到测试人员的构建过程中,JUnit 和 Ant 的结合可以实
施增量开发。 D、 JUnit是公开源代码的,可以进行二次开发。 C、可以方便地对Jnit进行扩展 编写原则: A、是简化测试的编写,这种简化包括测试框架的学习和实际测试 单元的编写 是使测试单元保持持久性 C、是可以利用既有的测试来编写相关的测试 113 JUnit的特征 A、使用断言方法判断期望值和实际值差异,返回 Boolean值。 测试驱动设备使用共同的初始化变量或者实例 C、测试包结构便于组织和集成运行。 支持图型交互模式和文本交互模式 114 JUnit框架与组成 A、对测试目标进行测试的方法与过程集合,可称为测试用例 B、测试用例的集合,可容纳多个测试用例( Testcase),将其称作测 试包( Testsuite) C、测试结果的描述与记录。( TestResult) D、测试过程中的事件监听者( TestListener) E、每一个测试方法所发生的与预期不一致状况的描述,称其测试 失败元素( TestFailure) F、 JUnit framework中的出错异常( Assertion Failed error)。 JUnit框架是一个典型的 Composite模式: TestSuite可以容纳任何派 生自Test的对象;当调用 Test Suite对象的run()方法是,会遍历自 己容纳的对象,逐个调用它们的run0)方法。(可参考《程序员》2003-6 期) 115JUnt的安装和配置 JUnit安装步骤分解 在htt:/ download. sourceforge. net/junt/中下载Jnit包并将Junt 压缩包解压到一个物理目录中(例如C:\Junt381)
施增量开发。 D、JUnit 是公开源代码的,可以进行二次开发。 C、可以方便地对 JUnit 进行扩展。 编写原则: A、是简化测试的编写,这种简化包括测试框架的学习和实际测试 单元的编写。 B、是使测试单元保持持久性。 C、是可以利用既有的测试来编写相关的测试。 1.1.3 JUnit 的特征 A、使用断言方法判断期望值和实际值差异,返回 Boolean 值。 B、测试驱动设备使用共同的初始化变量或者实例。 C、测试包结构便于组织和集成运行。 D、支持图型交互模式和文本交互模式。 1.1.4 JUnit 框架与组成 A、对测试目标进行测试的方法与过程集合,可称为测试用例 (TestCase)。 B、测试用例的集合,可容纳多个测试用例(TestCase),将其称作测 试包(TestSuite)。 C、测试结果的描述与记录。(TestResult) 。 D、测试过程中的事件监听者(TestListener)。 E、每一个测试方法所发生的与预期不一致状况的描述,称其测试 失败元素(TestFailure) F、JUnit Framework 中的出错异常(AssertionFailedError)。 JUnit 框架是一个典型的 Composite 模式:TestSuite 可以容纳任何派 生自 Test 的对象;当调用 TestSuite 对象的 run()方法是,会遍历自 己容纳的对象,逐个调用它们的 run()方法。(可参考《程序员》2003‐6 期)。 1.1.5 JUnit 的安装和配置 JUnit 安装步骤分解: 在 http://download.sourceforge.net/junit/中下载 JUnit 包并将 Junit 压缩包解压到一个物理目录中(例如 C:\Junit3.8.1)
记录 Junit. jar文件所在目录名(例如C:\Junt3.81 Junit jar)。 进入操作系统(以 Windows2000操作系统为准),按照次序点击“开 始设置控制面板 在控制面板选项中选择“系统”,点击“环境变量”,在“系统变量” 的“变量”列表框中选择“ CLASS-PATH”关键字(不区分大小写), 如果该关键字不存在则添加。 双击“ CLASS-PATH”关键字添加字符串“C:\ Junit3.81 Junta. jar”(注 意,如果已有别的字符串请在该字符串的字符结尾加上分号“;”), 这样确定修改后 Junit就可以在集成环境中应用了。 对于IDE环境,对于需要用到的 JUnit的项目增加到ib中,其设置 不同的IDE有不同的设置 12 JUnit架构分析 121接口分析 Test接口——运行测试和收集测试结果 Test接口使用了 Composite设计模式,是单独测试用例 ( Testcase),聚合测试模式( Testsuite)及测试扩展 ( TestDecorator)的共同接口。 它的 public int countTestCases()方法,它来统计这次测试有多 少个 Test case,另外一个方法就是 public void run Test Result), Test Result是实例接受测试结果,run方法执行 本次测试。 Test Case抽象类——定义测试中固定方法 Test case是Test接口的抽象实现,(不能被实例化,只能被继承) 其构造函数 Test Case(string name根据输入的测试名称name创建 个测试实例。由于每一个 Test case在创建时都要有一个名称, 若某测试失败了,便可识别出是哪个测试失败 TestCase类中包含的 setUp()、 tearDown(方法。 setUp(方法集中 初始化测试所需的所有变量和实例,并且在依次调用测试类中的 每个测试方法之前再次执行 setUp(方法。 tearDown()方法则是在 每个测试方法之后,释放测试程序方法中引用的变量和实例。 开发人员编写测试用例时,只需继承 TestCase,来完成run方法 即可,然后 JUnit获得测试用例,执行它的run方法,把测试结 果记录在 TestResult之中。 Assert静态类—系列断言方法的集合 Assert包含了一组静态的测试方法,用于期望值和实际值比对是 否正确,即测试失败, Assert类就会抛出一个 Assertion Failed error
记录 Junit.jar 文件所在目录名(例如 C:\Junit3.8.1\Junit.jar)。 进入操作系统(以 Windows2000 操作系统为准),按照次序点击“开 始 设置 控制面板”。 在控制面板选项中选择“系统”,点击“环境变量”,在“系统变量” 的“变量”列表框中选择“CLASS‐PATH”关键字(不区分大小写), 如果该关键字不存在则添加。 双击“CLASS‐PATH”关键字添加字符串“C:\Junit3.8.1\Junti.jar”(注 意,如果已有别的字符串请在该字符串的字符结尾加上分号“;”), 这样确定修改后 Junit 就可以在集成环境中应用了。 对于 IDE 环境,对于需要用到的 JUnit 的项目增加到 lib 中,其设置 不同的 IDE 有不同的设置 。 1.2 JUnit 架构分析 1.2.1 接口分析 Test 接口——运行测试和收集测试结果 Test 接口使用了 Composite 设计模式,是单独测试用例 (TestCase),聚合测试模式(TestSuite)及测试扩展 (TestDecorator)的共同接口。 它的 public int countTestCases()方法,它来统计这次测试有多 少个 TestCase,另外一个方法就是 public void run ( TestResult ),TestResult 是实例接受测试结果, run 方法执行 本次测试。 TestCase 抽象类——定义测试中固定方法 TestCase 是 Test 接口的抽象实现,(不能被实例化,只能被继承) 其构造函数TestCase(string name)根据输入的测试名称name创建 一个测试实例。由于每一个 TestCase 在创建时都要有一个名称, 若某测试失败了,便可识别出是哪个测试失败。 TestCase 类中包含的 setUp()、tearDown()方法。setUp()方法集中 初始化测试所需的所有变量和实例,并且在依次调用测试类中的 每个测试方法之前再次执行 setUp()方法。tearDown()方法则是在 每个测试方法之后,释放测试程序方法中引用的变量和实例。 开发人员编写测试用例时,只需继承 TestCase,来完成 run 方法 即可,然后 JUnit 获得测试用例,执行它的 run 方法,把测试结 果记录在 TestResult 之中。 Assert 静态类——一系列断言方法的集合 Assert 包含了一组静态的测试方法,用于期望值和实际值比对是 否正确,即测试失败,Assert 类就会抛出一个 AssertionFailedError
异常,jυUnit测试框架将这种错误归入 Failes并加以记录,同时标 志为未通过测试。如果该类方法中指定一个 String类型的传参则 该参数将被做为 Assertion Failed error异常的标识信息,告诉测试 人员改异常的详细信息。 JUnit提供了6大类31组断言方法,包括基础断言、数字断言、 字符断言、布尔断言、对象断言。 其中 assertEquals( Object expected, Object actua内部逻辑判断使 用 equals()方法,这表明断言两个实例的内部哈希值是否相等时 最好使用该方法对相应类实例的值进行比较。而 assertsame ( Object expected, Object actual)内部逻辑判断使用了Java运算 符“==”,这表明该断言判断两个实例是否来自于同一个引用 ( Reference),最好使用该方法对不同类的实例的值进行比对。 asser equals( String message, String expected, String actual)该方法对 两个字符串进行逻辑比对,如果不匹配则显示着两个字符串有差 异的地方。 Comparison Failure类提供两个字符串的比对,不匹配 则给出详细的差异字符。 TestSuite测试包类—多个测试的组合 Test Suite类负责组装多个 Test Cases。待测得类中可能包括了对 被测类的多个测试,而 Testsuit负责收集这些测试,使我们可以 在一个测试中,完成全部的对被测类的多个测试。 Testsuite类实现了Test接口,且可以包含其它的 Test suites。它 可以处理加入Test时的所有抛出的异常。 TestSuite处理测试用例有6个规约(否则会被拒绝执行测试) A测试用例必须是公有类( Public) B测试用例必须继承与 Test case类 C测试用例的测试方法必须是公有的( Public) D测试用例的测试方法必须被声明为void E测试用例中测试方法的前置名词必须是test F测试用例中测试方法误任何传递参数 n Testresult结果类和其它类与接口 TestResult结果类集合了任意测试累加结果,通过 TestResult实例 传递个每个测试的Run()方法。 TestResult在执行 Test Case是 如果失败会异常抛出 Test listener接口是个事件监听规约,可供 TestRunner类使用。 它通知 listener的对象相关事件,方法包括测试开始 startLes(Test test,测试结束 endTest( Testtest,错误,增加异常 add error(Test test. throwable t)和增加失败 add Failure(Test test, Assertion Failed Error t) Test Failure失败类是个“失败”状况的收集类,解释每次测试执 行过程中出现的异常情况。其 toString方法返回“失败”状况的 简要描述
异常,JUnit 测试框架将这种错误归入 Failes 并加以记录,同时标 志为未通过测试。如果该类方法中指定一个 String 类型的传参则 该参数将被做为 AssertionFailedError 异常的标识信息,告诉测试 人员改异常的详细信息。 JUnit 提供了 6 大类 31 组断言方法,包括基础断言、数字断言、 字符断言、布尔断言、对象断言。 其中 assertEquals(Object expcted,Object actual)内部逻辑判断使 用 equals()方法,这表明断言两个实例的内部哈希值是否相等时, 最好使用该方法对相应类实例的值进行比较。而 assertSame (Object expected,Object actual)内部逻辑判断使用了 Java 运算 符“==”,这表明该断言判断两个实例是否来自于同一个引用 (Reference),最好使用该方法对不同类的实例的值进行比对。 asserEquals(String message,String expected,String actual)该方法对 两个字符串进行逻辑比对,如果不匹配则显示着两个字符串有差 异的地方。ComparisonFailure 类提供两个字符串的比对,不匹配 则给出详细的差异字符。 TestSuite 测试包类——多个测试的组合 TestSuite 类负责组装多个 Test Cases。待测得类中可能包括了对 被测类的多个测试,而 TestSuit 负责收集这些测试,使我们可以 在一个测试中,完成全部的对被测类的多个测试。 TestSuite 类实现了 Test 接口,且可以包含其它的 TestSuites。它 可以处理加入 Test 时的所有抛出的异常。 TestSuite 处理测试用例有 6 个规约(否则会被拒绝执行测试) A 测试用例必须是公有类(Public) B 测试用例必须继承与 TestCase 类 C 测试用例的测试方法必须是公有的( Public ) D 测试用例的测试方法必须被声明为 Void E 测试用例中测试方法的前置名词必须是 test F 测试用例中测试方法误任何传递参数 n TestResult 结果类和其它类与接口 TestResult 结果类集合了任意测试累加结果,通过 TestResult 实例 传递个每个测试的 Run()方法。TestResult 在执行 TestCase 是 如果失败会异常抛出 TestListener 接口是个事件监听规约,可供 TestRunner 类使用。 它通知 listener 的对象相关事件,方法包括测试开始 startTest(Test test),测试结束 endTest(Test test),错误,增加异常 addError(Test test,Throwable t)和增加失败 addFailure(Test test,AssertionFailedError t) TestFailure 失败类是个“失败”状况的收集类,解释每次测试执 行过程中出现的异常情况。其 toString()方法返回“失败”状况的 简要描述
122 JUnit架构 JUnit的架构可以参照下图: Client Adapte ternata Servicel Internal Microkernel Servicel 13 JUnit设计模式 131简介 在本文中我们将匆匆一瞥其内中细节,并向你展示该框架本身是如何被构造的 我们细致地研究 JUint框架并思索如何来构造它。我们发现了许多不同层次上的教训 在本文中,我们将尝试着立刻与它们进行沟通,这是一个令人绝望的任务,但至少它 是在我们向你展示设计和构造一件价值被证实的软件的上下文中来进行的 我们引发了一个关于框架目标的讨论。在对框架本身的表达期间,目标将重复出现许 多小的细节中。此后,我们提出框架的设计和实现。设计将从模式(惊奇,惊奇)的 角度进行描述,并作为优美的程序来予以实现。我们总结了一些优秀的关于框架开发 的想法
1.2.2 JUnit 架构 JUnit 的架构可以参照下图: 1.3 JUnit 设计模式 1.3.1 简介 在本文中我们将匆匆一瞥其内中细节,并向你展示该框架本身是如何被构造的。 我们细致地研究 JUint 框架并思索如何来构造它。我们发现了许多不同层次上的教训。 在本文中,我们将尝试着立刻与它们进行沟通,这是一个令人绝望的任务,但至少它 是在我们向你展示设计和构造一件价值被证实的软件的上下文中来进行的。 我们引发了一个关于框架目标的讨论。在对框架本身的表达期间,目标将重复出现许 多小的细节中。此后,我们提出框架的设计和实现。设计将从模式(惊奇,惊奇)的 角度进行描述,并作为优美的程序来予以实现。我们总结了一些优秀的关于框架开发 的想法
132什么是 JUnit的目标呢? 首先,我们不得不回到开发的假定上去。如果缺少一个程序特性的自动测试 ( automated test),我们便假定其无法工作。这看起来要比主流的假定更加安全,主 流的假定认为如果开发者向我们保证一个程序特性能够工作,那么现在和将来其都会 永远工作。 从这个观点来看,当开发者编写和调试代码时,它们的工作并没有完成,它们还要必 须编写测试来演示程序能够工作。然而,每个人都太忙,他们要做的事情太多,他们 没有充足的时间用于测试。我已经有太多的代码需要编写,要我如何再来编写测试代 码?回答我,强硬的项目经理先生。因此,首要目标就是编写一个框架,在这个框架 中开发者能够看到实际来编写测试的希望之光。该框架必须要使用常见的工具,从而 学习起来不会有太多的新东西。其不能比完全编写一个新测试所必须的工作更多。必 须排除重复性的工作。 如果所有测试都这样去做的话,你将可以仅在一个调试器中编写表达式来完成。然而, 这对于测试而言尚不充分。告诉我你的程序现在能够工作,对我而言并没有什么帮助 因为它并没有向我保证你的程序从我现在集成之后的每一分钟都将会工作,以及它并 没有向我保证你的程序将依然能够工作五年,那时你已经离开了很长的时间 于是,测试的第二个目标就是生成可持续保持其价值的测试。除原作者以外的其他人 必须能够执行测试并解释其结果。应该能够将不同作者的测试结合起来并在一起运 行,而不必担心相互冲突。 最后,必须能够以现有的测试作为支点来生成新的测试。生成一个装置( setup)或 夹具( fixture)是昂贵的,并且一个框架必须能够对夹具进行重用,以运行不同的测 试。哦,还有别的吗? 133 JUnit的设计 JUnit的设计将以一种首次在 Patterns Generate Architectures(请参见" Patterns Generate Architectures", Kent Beck and Ralph Johnson, ECOOP94)中使用的风格来呈 现。其思想是通过从零开始来应用模式,然后一个接一个,直至你获得系统架构的方 式来讲解一个系统的设计。我们将提出需要解决的架构问题,总结用来解决问题的模 式,然后展示如何将模式应用于 JUnit。 1331由此开始一 TestCase 首先我们必须构建一个对象来表达我们的基本概念, Testcase(测试案例)。开发者经 常在头脑中存在着测试案例,但在实现它们的时候却采用了许多不同的方式一 1.打印语句 2.调试器表达式 3测试脚本
1.3.2 什么是 JUnit 的目标呢? 首先,我们不得不回到开发的假定上去。如果缺少一个程序特性的自动测试 (automated test),我们便假定其无法工作。这看起来要比主流的假定更加安全,主 流的假定认为如果开发者向我们保证一个程序特性能够工作,那么现在和将来其都会 永远工作。 从这个观点来看,当开发者编写和调试代码时,它们的工作并没有完成,它们还要必 须编写测试来演示程序能够工作。然而,每个人都太忙,他们要做的事情太多,他们 没有充足的时间用于测试。我已经有太多的代码需要编写,要我如何再来编写测试代 码?回答我,强硬的项目经理先生。因此,首要目标就是编写一个框架,在这个框架 中开发者能够看到实际来编写测试的希望之光。该框架必须要使用常见的工具,从而 学习起来不会有太多的新东西。其不能比完全编写一个新测试所必须的工作更多。必 须排除重复性的工作。 如果所有测试都这样去做的话,你将可以仅在一个调试器中编写表达式来完成。然而, 这对于测试而言尚不充分。告诉我你的程序现在能够工作,对我而言并没有什么帮助, 因为它并没有向我保证你的程序从我现在集成之后的每一分钟都将会工作,以及它并 没有向我保证你的程序将依然能够工作五年,那时你已经离开了很长的时间。 于是,测试的第二个目标就是生成可持续保持其价值的测试。除原作者以外的其他人 必须能够执行测试并解释其结果。应该能够将不同作者的测试结合起来并在一起运 行,而不必担心相互冲突。 最后,必须能够以现有的测试作为支点来生成新的测试。生成一个装置(setup)或 夹具(fixture)是昂贵的,并且一个框架必须能够对夹具进行重用,以运行不同的测 试。哦,还有别的吗? 1.3.3 JUnit 的设计 JUnit 的设计将以一种首次在 Patterns Generate Architectures(请参见"Patterns Generate Architectures", Kent Beck and Ralph Johnson, ECOOP 94)中使用的风格来呈 现。其思想是通过从零开始来应用模式,然后一个接一个,直至你获得系统架构的方 式来讲解一个系统的设计。我们将提出需要解决的架构问题,总结用来解决问题的模 式,然后展示如何将模式应用于 JUnit。 1.3.3.1 由此开始-TestCase 首先我们必须构建一个对象来表达我们的基本概念,TestCase(测试案例)。开发者经 常在头脑中存在着测试案例,但在实现它们的时候却采用了许多不同的方式- 1. 打印语句 2. 调试器表达式 3. 测试脚本
如果我们想要轻松地操纵测试,就必须将它们构建成对象。这将会获取到一个仅仅是 隐藏在开发者头脑中的测试,并使之具体化,其支持我们创建测试的目标,即能够持 续地保持它们的价值。同时,对象的开发者比较习惯于使用对象来进行开发,因此将 测试构建成对象的决定支持我们的目标一使测试的编写更加吸引人(或至少是不太华 丽 Command(命令)模式(请参见 Gamma,E,etal. Design Patterns: Elements of reusable Object-Oriented Software, Addison- Wesley, Reading,MA,1995)则能够比较好地满足我 们的需求。摘引其意图( intent),“将一个请求封装成一个对象,从而使你可用不同 的请求对客户进行参数化;对请求进行排队或记录请求日志…” Command告诉我们 可以为一个操作生成一个对象并给出它的一个“ execute(执行)”方法。以下代码定 义了 TestCase类: public abstract class TestCase implements Test 因为我们期望可以通过继承来对该类进行重用,我们将其声明为“ public abstract 暂时忽略其实现接口Test的事实。鉴于当前设计的需要,你可以将 Test case看作是 个孤立的类。 每一个 Testcase在创建时都要有一个名称,因此若一个测试失败了,你便可识别出失 败的是哪个测试。 public abstract class TestCase implements Test i private final String fName public TestCase(String name) public abstract void run( 为了阐述JUnt的演变过程,我们将使用图( diagram)来展示构架的快照( snapshot) 我们使用的标记很简单。其使用包含相关模式的尖方框来标注类。当类在模式中的角 色(role)显而易见时,则仅显示模式的名称。如果角色并不清晰,则在尖方框中增 加与该类相关的参与者的名称。该标记可使图的混乱度降到最小限度,并首次见诸于 Applying Design Patterns in Java (H L Gamma, E, Applying Design Patterns in Java, in Java gems, SIGS Reference Library,1997)。图1展示了这种应用于 Testcase中的标记。 由于我们是在处理一个单独的类并且没有不明确的地方,因此仅显示模式的名称。 Testcase Command runo
如果我们想要轻松地操纵测试,就必须将它们构建成对象。这将会获取到一个仅仅是 隐藏在开发者头脑中的测试,并使之具体化,其支持我们创建测试的目标,即能够持 续地保持它们的价值。同时,对象的开发者比较习惯于使用对象来进行开发,因此将 测试构建成对象的决定支持我们的目标-使测试的编写更加吸引人(或至少是不太华 丽)。 Command(命令)模式(请参见 Gamma, E., et al. Design Patterns: Elements of Reusable Object‐Oriented Software, Addison‐Wesley, Reading, MA, 1995)则能够比较好地满足我 们的需求。摘引其意图(intent),“将一个请求封装成一个对象,从而使你可用不同 的请求对客户进行参数化;对请求进行排队或记录请求日志...”Command 告诉我们 可以为一个操作生成一个对象并给出它的一个“execute(执行)”方法。以下代码定 义了 TestCase 类: public abstract class TestCase implements Test { … } 因为我们期望可以通过继承来对该类进行重用,我们将其声明为“public abstract”。 暂时忽略其实现接口 Test 的事实。鉴于当前设计的需要,你可以将 TestCase 看作是 一个孤立的类。 每一个 TestCase 在创建时都要有一个名称,因此若一个测试失败了,你便可识别出失 败的是哪个测试。 public abstract class TestCase implements Test { private final String fName; public TestCase(String name) { fName= name; } public abstract void run(); … } 为了阐述 JUnit 的演变过程,我们将使用图(diagram)来展示构架的快照(snapshot)。 我们使用的标记很简单。其使用包含相关模式的尖方框来标注类。当类在模式中的角 色(role)显而易见时,则仅显示模式的名称。如果角色并不清晰,则在尖方框中增 加与该类相关的参与者的名称。该标记可使图的混乱度降到最小限度,并首次见诸于 Applying Design Patterns in Java(请参见 Gamma, E., Applying Design Patterns in Java, in Java Gems, SIGS Reference Library, 1997)。图 1 展示了这种应用于 TestCase 中的标记。 由于我们是在处理一个单独的类并且没有不明确的地方,因此仅显示模式的名称
图1 Test case应用 Command 1.3.32空白填充-run0 接下来要解决的问题是给开发者一个便捷的“地方”,用于放置他们的夹具代码和测 试代码。将 TestCase声明为 abstract是指开发者希望通过子类化( subclassing)来对 Test case进行重用。然而,如果我们所有能作的就是提供一个只有一个变量且没有行 为的超类,那么将无法做太多的工作来满足我们的首个目标一使测试更易于编写。 幸运的是,所有测试都具有一个共同的结构一建立一个测试夹具,在夹具上运行一些 代码,检査结果,然后清理夹具。这意味着每一个测试将与一个新的夹具一起运行, 并且一个测试的结果不会影响到其它测试的结果。这支持测试价值最大化的目标。 Template Method(模板方法)比较好地涉及到我们的问题。摘引其意图,“定义一个 操作中算法的骨架,并将一些步骤延迟到子类中。 Template Method使得子类能够不 改变一个算法的结构便可重新定义该算法的某些特定步骤。”这完全恰当。我们就是 想让开发者能够分别来考虑如何编写夹具(建立和拆卸)代码,以及如何编写测试代 码。不管怎样,这种执行的次序对于所有测试都将保持相同,而不管夹具代码如何编 写,或测试代码如何编写。 Template Method如下 ublic void run( t setUp t(); tearDown(; 这些方法被缺省实现为“什么都不做” protected void run Test(i protected void setup protected void tear Down( 由于 setUp和 tear Down会被用来重写( override),而且其将由框架来进行调用,因 此我们将其声明为 protected。我们的第二个快照如图2所示。 Testcase run Temp late Method setUp 图2 TestCase. run(应用 Template Method
图 1 TestCase 应用 Command 1.3.3.2 空白填充-run() 接下来要解决的问题是给开发者一个便捷的“地方”,用于放置他们的夹具代码和测 试代码。将 TestCase 声明为 abstract 是指开发者希望通过子类化(subclassing)来对 TestCase 进行重用。然而,如果我们所有能作的就是提供一个只有一个变量且没有行 为的超类,那么将无法做太多的工作来满足我们的首个目标-使测试更易于编写。 幸运的是,所有测试都具有一个共同的结构-建立一个测试夹具,在夹具上运行一些 代码,检查结果,然后清理夹具。这意味着每一个测试将与一个新的夹具一起运行, 并且一个测试的结果不会影响到其它测试的结果。这支持测试价值最大化的目标。 Template Method(模板方法)比较好地涉及到我们的问题。摘引其意图,“定义一个 操作中算法的骨架,并将一些步骤延迟到子类中。Template Method 使得子类能够不 改变一个算法的结构便可重新定义该算法的某些特定步骤。”这完全恰当。我们就是 想让开发者能够分别来考虑如何编写夹具(建立和拆卸)代码,以及如何编写测试代 码。不管怎样,这种执行的次序对于所有测试都将保持相同,而不管夹具代码如何编 写,或测试代码如何编写。 Template Method 如下: public void run() { setUp(); runTest(); tearDown(); } 这些方法被缺省实现为“什么都不做”: protected void runTest() { } protected void setUp() { } protected void tearDown() { } 由于 setUp 和 tearDown 会被用来重写(override),而且其将由框架来进行调用,因 此我们将其声明为 protected。我们的第二个快照如图 2 所示。 图 2 TestCase.run()应用 Template Method