单元测试与测试驱动开发_第1页
单元测试与测试驱动开发_第2页
单元测试与测试驱动开发_第3页
单元测试与测试驱动开发_第4页
单元测试与测试驱动开发_第5页
已阅读5页,还剩52页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、软件软件测试测试技术技术Te s t i n g AND Developing软件测试过程与测试模型广东岭南职业技术学院2本章目标 掌握测试驱动开发的基本概念 掌握驱动的基本流程 掌握测试驱动的所采用的技术及工具 Junit测试31-1 基本概念 为什么会出现测试驱动开发?l 当有一个新的开发任务时,往往第一个念头就是如何去实现 它呢?l “应该是这么做的吧,嗯,差不多就是这样的” 。l 抓起任务就开始编码,一边写,一边修改和设计。l 时间这么紧!我还是先实现任务吧,然后再好好测试。l 还是不工作,时间不多了。不管了,还是先做个实现,以后再来整理代码吧。l 我已经单步调试了好几次了,遍历了所有

2、可能的分支,应该不会有问题了,提交,今天可以好好休息一下了。l 要不要写单元测试把我刚才单步调试的步骤写下来啊?那样是很好,但工作量很大哦。l 这样的情况要作自动测试太复杂了。还是手工测试一下吧。l 程序员应该做些有创意的东西,这样才有趣啊。l 测试是QA的事,我为什么要做啊,我做了他们干什么啊。41-1 基本概念 为什么会出现测试驱动开发?l 奇怪了,怎么代码跟开发文档上有这么大的差别啊。l 这段代码究竟想表达什么意思? l 代码现在越来越乱了,我都不敢修改代码了,修改了这个地方,天晓得会引起多少别的地方出错啊!l 这个地方的代码怎么好象在那个地方看到过啊?这个程序里怎么会有这么多的重复代码

3、呢?l 开发部在干什么啊,BUG怎么这么多,他们有没有自己先测试一下啊。l 这下好了,让他们修改了一个BUG,现在一下子来了这么多的BUG。l他们到底在搞什么啊,有没有从用户的角度考虑啊,我新增一个采购订单,订单项竟然可以输入负数。 51-1 基本概念有办法可以解决上面的矛盾吗?61-1 基本概念什么是测试驱动?测试驱动是一种开发形式:1.首先要编写测试代码2.除非存在相关测试,否则不编写任何的产品代码3.由测试来决定需要编写什么样的代码4.要求维护一套详尽的测试集71-1 基本概念 测试驱动所要达到的目标clean code that work 测试驱动所追求的目标就是代码整洁可用,其实现的

4、规则就是:1.只有测试失败时,我们才写代码2.消除重复设计,优化设计结构81-2 基本流程 测试驱动开发的基本流程l定义应用程序的要求l熟悉应用程序的功能区域,确定要使用的单项功能项或功能要求l创建验证要求的测试列表l为功能或要求定义接口和类l编写测试代码l运行测试l根据测试生成产品代码l重新运行测试,根据测试修改产品代码,直到所有测试都通过l整理代码l重复上面的步骤91-2 基本流程 测试驱动开发的基本流程101-3 技术及工具 技术及工具介绍Eclipse是一个集成开发工具的通用平台,因为任何人都可以免费获得源码以及软件本身的方便,因此成为许多人的喜爱,junit是供Java编码人员做单元

5、测试之用,在eclipse中使用junit测试Java程序能够体现测试驱动开发的测试思想,本课通过实例对在eclipse中使用junit测试的方法进行了分析。 111-3 技术及工具 Eclipse介绍Eclipse 是IBM投入巨资开发的替代IBM Visual Age for Java 的下一代IDE开发环境,在开发结束以后IBM把该软件赠与了国际开放源代码团体,任何人都能轻易地下载到Eclipse的源代码。软件可以集成很多软件开发工具供应商的产品,任何开发工具厂商都可以将开发工具或许主件加入到Eclipse平台,用户可以通过相同的接口使用不同的工具,也就是在一个集成环境中使用不同的开发工

6、具。 121-3 技术及工具 JUnit介绍JUnit是一款由Erich Gamma(设计模式的作者)和Kent Beck(极限编程的提出者)编写的开源的回归测试框架,供Java编码人员做单元测试之用,可以从网站上免费获得。因为两种软件的源码都能从网上免费下载,因此受到越来越多的开发人员、测试人员的喜爱。 131-4 DEMO -一个简单的流程 TDD意味着您不仅需要为每一段代码编写测试用例,而且意味着测试优先。测试用例用来定义代码需要做什么。在完成相应的代码之后,运行测试用例来保证代码确实符合测试用例的规定。 创建一个简单的Java类 创建一个测试类来执行这个Jav

7、a类 使用JUnit框架 学习构造函数 重构您所写的代码Before: 使用了该元数据的方法在每个测试方法执行之前都要执行一次。 After: 使用了该元数据的方法在每个测试方法执行之后要执行一次。 注意:Before和After标示的方法只能各有一个。这个相当于取代了JUnit以前版本中的setUp和tearDown方法,当然你还可以继续叫这个名字,不过JUnit不会霸道的要求你这么做了。 Test(expected=*.class) 在JUnit4.0之前,对错误的测试,我们只能通过fail来产生一个错误,并在try块里面assertTrue(true)来测试。现在,通过Test元数据中的

8、expected属性。expected属性的值是一个异常的类型 Test(timeout=xxx): 该元数据传入了一个时间(毫秒)给测试方法, 如果测试方法在制定的时间之内没有运行完,则测试也失败。 ignore: 该 元数据标记的测试方法在测试中会被忽略。当测试的方法还没有实现,或者测试的方法已经过时,或者在某种条件下才能测试该方法(比如需要一个数据库联接,而 在本地测试的时候,数据库并没有连接),那么使用该标签来标示这个方法。同时,你可以为该标签传递一个String的参数,来表明为什么会忽略这个测试方 法。比如:lgnore(“该方法还没有实现”),在执行的时候,仅会报告该方法没有实现,

9、而不会运行测试方法。1 JUnit JUnit 是 Java 社区中知名度最高的单元测试工具。它诞生于 1997 年,由 Erich Gamma 和 Kent Beck 共同开发完成。其中 Erich Gamma 是经典著作设计模式:可复用面向对象软件的基础一书的作者之一,并在 Eclipse 中有很大的贡献;Kent Beck 则是一位极限编程(XP)方面的专家和先驱。 麻雀虽小,五脏俱全。JUnit 设计的非常小巧,但是功能却非常强大。Martin Fowler 如此评价 JUnit:在软件开发领域,从来就没有如此少的代码起到了如此重要的作用。它大大简化了开发人员执行单元测试的难度,特别是

10、 JUnit 4 使用 Java 5 中的注解(annotation)使测试变得更加简单。 Junit测试是程序员测试,即所谓白盒测试,因为程序员知道被测试的软件如何(How)完成功能和完成什么样(What)的功能。Junit本质上是一套框架,即开发者制定了一套条条框框,遵循这此条条框框要求编写测试代码,如继承某个类,实现某个接口,就可以用Junit进行自动测试了。由于Junit相对独立于所编写的代码,可以测试代码的编写可以先于实现代码的编写,XP 中推崇的 test first design的实现有了现成的手段:用Junit写测试代码,写实现代码,运行测试,测试失败,修改实现代码,再运行测试

11、,直到测试成功。以后对代码的修改和优化,运行测试成功,则修改成功。Java 下的 team 开发,采用 cvs(版本控制) + ant(项目管理) + junit(集成测试) 的模式时,通过对ant的配置,可以很简单地实现测试自动化。对不同性质的被测对象,如Class,Jsp,Servlet,Ejb等,Junit有不同的使用技巧,以后慢慢地分别讲叙。以下以Class测试为例讲解,除非特殊说明。 (1) JUnit 测试框架 测试Fixtures: 是一组认定被测对象或被测程序单元成功的预定条件或预期结果的设定。 Fixtures就是被测试的目标,可以是一个对象或者一组相关的对象,或一个函数。

12、测试集:一组测试用例,这些用例要求有相同测试Fixtures。 测试执行 : 单元测试的执行可以按照下面的方式进行: Setup(); /*首先,要建立针对被测程序单元的独立测试环境*/ . /*然后,编写所有测试例子的测试体/测试程序 */ Teardown(); /*最后,无论测试成功与否,都要将被测程序的测试还击功能进行清理,以免影响后续的测试*/ 测试断言:实际上就是验证被测试程序在测试中的行为或状态的一个宏或函数,断言失败实际上就是引发异样,终止测试的执行。(2) JUnit 测试流程写测试用例的步骤包括:(1)对Fixtures进行初始化,以及其他初始化操作。比如:生成一组被测试的

13、对象,初始化。(2)按照要测试的某个功能或流程Fixtures进行操作。(3)验证结果是否正确。(4) 对Fixtures的以及其他的资源释放等做清理工作。对多个测试用例,通常步骤(1)、(2)部分代码是相似的,JUNIT在很多地方引入了Setup()和Teardown();虚函数。可以在Setup()中完成步骤(1)的初始化代码,在Teardown()中完成(4)的代码,具体测试用例函数中只需要完成步骤(2)(3)部分的代码即可,运行JUNIT 会自动为每个测试用例函数运行Setup(),之后运行Teardown(),这样测试用例子之间就不会产生交叉影响。对Fixtures的所有测试用例可以

14、被封装在一个Junit:TestFixtures的子类(命名惯例是CassName Test)中。然后定义这个Fixtures 的Setup()和Teardown()函数,为每个测试用例定义一个测试函数(命名惯例为testXXX)。(3) Junit 特征使用断言方法来判断期望值和实际值的差异,返回Boolean值。测试驱动设备使用共同的初始化变量或实例。测试包结构便于组织和集成运行。支持图形交互模式和文本交互模式.Junit共有7个包,核心包是junit.framework和junit.runner。 framework负责整个测试对象的构架, runner包负责测试驱动.Junit有4个重

15、要的类:testsuite testcase testresult属于framework包;testrunner在不同的环境下是不同的如果使用的是文本测试环境,就用junit.textui.testrunner.(4) Junit各个类的职责:testsuite :负责收集testcase 所执行的结果,将结果分两类:客户可预测的failure和没有预测的error.同时负责将测试结果转发到testlistener(该接口由testrunner继承)进行处理.Testrunner:客户对象调用的起点,负责对整个测试流程进行跟踪.能够显示返回的测试结果,并且报告测试的进度.Testresult:

16、负责包装和运行所有的testcase.Testcase:客户测试类所要继承的类,负责测试时对客户类进行初始化以及测试方法调用. 另外有两个重要接口:test和testlistener Test:包括2个方法 run()和counttestcases(),用于对测试动作特征的提取. Testlistener:包括4个方法: adderror() 、 addfailure() 、starttest() 、endtest(),用于对测试结果的处理和测试驱动过程的动作特征的提取.(5)Junit框架的组成对测试目标进行测试的方法与过程集合,可称为(testcase)测试用例的集合,可容纳多个测试用例(

17、testcase),将其称为测试包(testsuite).测试结果的描述与记录(testresult).测试过程中的事件监听者(testlistener).每个测试方法所发生的与预期不一致的状况的描述,称其测试失败元素(testfailure).Juni framework 中的出错异常(assertionfailederror).Junit框架是一个典型composite模式: testsuite可以容纳任何派生自test的对象;当调用testsuited对象run()方法时,会遍历自己容纳的对象,逐个调用他们的run()方法。2 、 Junit单元测试环境建立 两种情况: (a)最直接的方

18、式:配置Junit,通过命令行建立。 (b)使用Eclipse中的Junit插件来建立。注意:使用Junit的前提是系统中已经安装Java 的JDK,并正确加入了系统环境变量。 (i)独立Junit测试环境的建立 (1) 去Junit主页下载程序包junit.zip(2) 将junit.zip解压缩到硬盘上(C:Junit)(3) 将junit.jar和C:unit junit加入到环境变量classpath (默认的class文件路径变量)中,加入后者只因为测试例程在那个目录下。右击“我的电脑” ,在属性-高级-环境变量中,如果没有classpath这个变量,则需要手动添加一个。单击“系统变

19、量”下的新建按钮。注意不要将junit.jar放在jdk的extension目录下。(4) 测试安装是否成功。方法一 :批处理文本方式。运行命令 C: java junit.textui.TestRunner,结果如右图。 方法二 :AWT图形测试运行方式。运行命令 C: java junit.awtui.TestRunner方法三 :基于Swing图形测试运行方式。运行命令 C: java junit.awtui.TestRunner如果上述命令都运行无误,则安装成功。(ii)使用Eclipse中的Junit插件来建立。新建一个 Java 工程 点击文件-新建-项目,选择Java项目,点击下

20、一步。起一个项目名称,例如目 coolJUnit 。再来配置一下Eclipse 打开项目 coolJUnit 的属性页 在工具条上右键项目-build path,选择Java构建路径,选择add external jars,浏览Junit被存储的目录,选择junit.jar,点击打开。你将会看见JUnit出现在库的列表中。如图1所示。编写或者导入待测程序 将待测程序放入此项目中或者编写测试程序。写测试程序 在此Java项目上点击右键,选择新建-其他.展开java选项。选择JUnit。选择JUnitTestCase。即可进行测试程序的编写。 定义一些以“test”开头的无返回方法,在此方法种调用

21、assert*()函数,它用来进行测试。 运行测试程序 点击Run As-JUnit Test即可进行测试。图1 为项目添加 JUnit 库 因为单元测试代码是不会出现在最终产品中的。建议您分别为单元测试代码与被测试代码创建单独的目录,并保证测试代码和被测试代码使用相同的包名。这样既保证了代码的分离,同时还保证了查找的方便。遵照这条原则,我们在项目 coolJUnit 根目录下添加一个新目录 testsrc,并把它加入到项目源代码目录中(加入方式见 图2)。 图2 修改项目源代码目录 Junit单元测试的方法(i)独立的的Junit应用Junit基本使用步骤:- 创建从junit.framew

22、ork.TestCase派生unit test需要test- 书写测试思路方法提供类似于如下签名测试思路方法:public void testXXXXX;- 编译书写完test 后编译所写test 类- 运行启动junit test runner来运行这个testJunit提供了2个基本test runner:界面和图形界面启动命令分别如下: a 图形界面: java junit.swingui.TestRunner XXXXX b 界面: java junit.textui.TestRunner XXXXXJUnit 将测试失败的情况分为两种:failure 和 error。Failure

23、一般由单元测试使用的断言方法判断失败引起,它表示在测试点发现了问题;而 error 则是由代码异常引起,这是测试目的之外的发现,它可能产生于测试代码本身的错误(测试代码也是代码,同样无法保证完全没有缺陷),也可能是被测试代码中的一个隐藏的bug。再次运行测试,绿条又重现眼前。通过对 WordDealUtil.wordFormat4DB 比较全面的单元测试,现在的代码已经比较稳定,可以作为 API 的一部分提供给其它模块使用了。 (1)使用例子 import junit.frmework.TestCase; public TestSample extends TestCa public void

24、 public void testMethod1 assertTrue( true); (2) setUp和tearDown这两个是junit framework中提供测试思路方法. setUp在每个测试思路方法前被负责化测试思路方法所需要测试环境;tearDown在每个测试思路方法被后被负责撤销测试环境。它们和测试思路方法关系可以描述如下: 测试开始 - Up - testXXXX - tearDown -测试结束(3)使用例子:import junit.frmework.TestCase;public TestSample extends TestCaprotected void Up/化

25、public void testMethod1assertTrue( true);potected void tearDown/撤销化5. 区分fail、exception - fail期望出现产生原因:assert出错(如assertFalse(true); fail产生(如fail()- exception不期望出现属于unit test运行时抛出异常,它和普通代码运行过程中抛出runtime异常属于一种类型对于assert、fail等请参见junitjavadoc(6) 使用例子import junit.frmework.TestCase;public TestSample extend

26、s TestCaprotected void Up/化public void testMethod1tryboolean b= assertTrue( b);throw Exception( “This is a test.”);fail( “Unable po.”); /不可能到达catch(Exception e)fail( “Yes, I catch u”); /应该到达点potected void tearDown/撤销化(7)组装TestSuite运行更多test在junit中Test、TestCase和TestSuite 3者组成了composiste pattern,通过组装自己

27、TestSuite可以完成对添加到这个TestSuite中所有TestCase,而且这些定TestSuite还可以组装成更大TestSuite.这样同时也方便了对于不断增加TestCase管理和维护.它另个好处就是可以从这个TestCase树任意个节点(TestSuite或TestCase)开始来完成这个节点以下所有TestCase,提高了unit test灵活性。(8) 使用例子:import junit.framework.Test;import junit.framework.TestSuite;public TestAllpublic TestAll/定义个suite对于junit作用

28、可以视为类似于java应用public Test suiteTestSuite suite = TestSuite(Running all tests.);suite.addTestSuite( TestCase1.);suite.addTestSuite( TestCase2.);suite; (9) 使用Ant junit task我们除了使用java来直接运行junit的外我们还可以使用junit提供junit task和ant结合来运行涉及几个主要ant task如下: - 定义个junit task - 位于中运行多个TestCase - 位于中运行单个TestCase - 位于中定

29、义个测试结果输出格式 - 定义个junitreport task - 位于中输出个junit report 具体语法请参见相关文档(10) 使用例子:Junit单元测试的方法(ii)Eclipse中的Junit应用(1)常见一个新的Java项目,然后创建一个简单的Java类,如图5所示。(2)按照前面介绍的方式,为Cat类创建一个Junit测试类,如图6所示。注意图中下标线标注的代码被修改过,这是为了测试Junit测试不通过的情况。图7 未通过的测试图8 通过的测试现在我们得到了一条 JUnit 的最佳实践:单元测试代码和被测试代码使用一样的包,不同的目录。 工具类 WordDealUtil

30、中的静态方法 wordFormat4DB 是专用于处理 Java 对象名称向数据库表名转换的方法(您可以在代码注释中可以得到更多详细的内容)。下面是第一次编码完成后大致情形: package com.ai92.cooljunit; import java.util.regex.Matcher; import java.util.regex.Pattern; /* * 对名称、地址等字符串格式的内容进行格式检查 * 或者格式化的工具类 * * author Ai92 */ public class WordDealUtil /* * 将Java对象名称(每个单词的头字母大写)按照 * 数据库命名

31、的习惯进行格式化 格式化后的数据为小写字母,并且使用下划线分割命名单词 * * 例如:employeeInfo 经过格式化之后变为 employee_info * * param name Java对象名称 */ public static String wordFormat4DB(String name) Pattern p = Ppile(A-Z); Matcher m = p.matcher(name); StringBuffer sb = new StringBuffer(); while(m.find() m.appendReplacement(sb, _+m.group(); re

32、turn m.appendTail(sb).toString().toLowerCase(); 它是否能按照预期的效果执行呢?尝试为它编写 JUnit 单元测试代码如下: package com.ai92.cooljunit; import static org.junit.Assert.assertEquals; import org.junit.Test; public class TestWordDealUtil /测试wordFormat4DB正常运行的情况 Test public void wordFormat4DBNormal() String target = employeeI

33、nfo; String result = WordDealUtil.wordFormat4DB(target); assertEquals(employee_info, result); 测试类 TestWordDealUtil 之所以使用“Test”开头,完全是为了更好的区分测试类与被测试类。测试方法 wordFormat4DBNormal 调用执行被测试方法 WordDealUtil.wordFormat4DB,以判断运行结果是否达到设计预期的效果。需要注意的是,测试方法 wordFormat4DBNormal 需要按照一定的规范书写: 1. 测试方法必须使用注解 org.junit.Te

34、st 修饰。 2. 测试方法必须使用 public void 修饰,而且不能带有任何参数。 测试方法中要处理的字符串为“employeeInfo”,按照设计目的,处理后的结果应该为“employee_info”。assertEquals 是由 JUnit 提供的一系列判断测试结果是否正确的静态断言方法(位于类 org.junit.Assert 中)之一,我们使用它将执行结果 result 和预期值“employee_info”进行比较,来判断测试是否成功。 看看运行结果如何。在测试类上点击右键,在弹出菜单中选择 Run As JUnit Test。运行结果如下图所示:图3 JUnit 运行成功

35、界面 绿色的进度条提示我们,测试运行通过了。但现在就宣布代码通过了单元测试还为时过早。记住:您的单元测试代码不是用来证明您是对的,而是为了证明您没有错。因此单元测试的范围要全面,比如对边界值、正常值、错误值得测试;对代码可能出现的问题要全面预测,而这也正是需求分析、详细设计环节中要考虑的。显然,我们的测试才刚刚开始,继续补充一些对特殊情况的测试: public class TestWordDealUtil /测试 null 时的处理情况 Test public void wordFormat4DBNull() String target = null; String result = Word

36、DealUtil.wordFormat4DB(target); assertNull(result); /测试空字符串的处理情况 Test public void wordFormat4DBEmpty() String target = ; String result = WordDealUtil.wordFormat4DB(target); assertEquals(, result); /测试当首字母大写时的情况 Test public void wordFormat4DBegin() String target = EmployeeInfo; String result = WordDe

37、alUtil.wordFormat4DB(target); assertEquals(employee_info, result); /测试当尾字母为大写时的情况 Test public void wordFormat4DBEnd() String target = employeeInfoA; String result = WordDealUtil.wordFormat4DB(target); assertEquals(employee_info_a, result); /测试多个相连字母大写时的情况 Test public void wordFormat4DBTogether() String target = employeeAInfo; String result = WordDealUtil.wordFormat4DB(target); assertEquals(employee_a_info, result); 再次运行测试。很遗憾,JUnit 运行

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论