Showing posts with label junit. Show all posts
Showing posts with label junit. Show all posts

Tuesday, April 28, 2009

JUnit

更多精彩请到 http://www.139ya.com

JUnit 学习笔记: http://caterpillar.onlyfun.net/Gossip/JUnit/JUnitGossip.htm

JUnit设计模式分析 : http://luogankun.javaeye.com/category/60169

junit 实战: http://www.iceshi.com/html/40/category-catid-140.html

JUnit测试框架使用介绍 : http://zhangjunhd.blog.51cto.com/113473/132553

测试是否抛出正确的异常 : http://book.csdn.net/bookfiles/153/1001536549.shtml

JUnit入门

更多精彩请到 http://www.139ya.com


 一、简介

  JUnit是一个开源的java单元测试框架。在1997年,由 Erich Gamma 和 Kent Beck 开发完成。这两个牛人中 Erich Gamma 是 GOF 之一;Kent Beck 则在 XP 中有重要的贡献(你觉得眼熟一点都不奇怪)。
  正如常言道:“麻雀虽小,五脏俱全。” JUnit设计的非常小巧,但是功能却非常强大。
  下面是JUnit一些特性的总结:
  1) 提供的API可以让你写出测试结果明确的可重用单元测试用例
  2) 提供了三种方式来显示你的测试结果,而且还可以扩展
  3) 提供了单元测试用例成批运行的功能
  4) 超轻量级而且使用简单,没有商业性的欺骗和无用的向导
  5) 整个框架设计良好,易扩展
  对不同性质的被测对象,如Class,Jsp,Servlet,Ejb等,Junit有不同的使用技巧。由于本文的性质,以下仅以Class测试为例。

  二、下载

  点击http://www.junit.org可以下载到最新版本的JUnit,本文使用的为3.8.1版。至于安装或者配置之类,你只需要轻松的将下载下来的压缩包中的jar文件,放到你工程的classpath中就可以了。
  这样,你的系统中就可以使用JUnit编写单元测试代码了(是不是很简单)!

  三、HelloWorld

  记得在几乎每本语言教学书上都能找到HelloWorld这个入门代码。今天在这里,我们也从一个简单到根本不用单元测试的例子入手。这是一个只会做两数加减的超级简单的计算器(小学一年级必备极品)。代码如下:

  public class SampleCalculator
  {
   public int add(int augend , int addend)
   {
   return augend + addend ;
   }

   public int subtration(int minuend , int subtrahend)

   {

   return minuend - subtrahend ;

   }

  }

  将上面的代码编译通过。下面就是我为上面程序写的一个单元测试用例:

  //请注意这个程序里面类名和方法名的特征
  import junit.framework.TestCase;
  public class TestSample extends TestCase

  {

   public void testAdd()

   {

  SampleCalculator calculator = new SampleCalculator();

   int result = calculator.add(50 , 20);

   assertEquals(70 , result);

   }

   public void testSubtration()

   {

   SampleCalculator calculator = new SampleCalculator();

   int result = calculator.subtration(50 , 20);

   assertEquals(30 , result);

   }

  }

  好了,在DOS命令行里面输入javac TestSample.java 将测试类编译通过。然后再输入 java junit.swingui.TestRunner TestSample 运行测试类,你会看到如下的窗口。

  绿色说明单元测试通过,没有错误产生;如果是红色的,则就是说测试失败了。这样一个简单的单元测试就完成了.

  按照框架规定:编写的所有测试类,必须继承自junit.framework.TestCase类;里面的测试方法,命名应该以Test开头,必须是 public void 而且不能有参数;而且为了测试查错方便,尽量一个TestXXX方法对一个功能单一的方法进行测试;使用assertEquals等 junit.framework.TestCase中的断言方法来判断测试结果正确与否。

  你可以对比着上面测试类中的实现来体会下规定——很简单!而且你在这个测试类中有加入多少个测试方法,就会运行多少个测试方法。

  四、向前一步

  学完了HelloWorld,你已经可以编写标准的单元测试用例了。但是还有一些细节,这里还要说明一下。不要急,很快的!
  另外你是否注意到,上面弹出窗口的一个细节,在绿条下面有Errors、Failures统计。这两者有何区别呢?
  Failures作为单元测试所期望发生的错误,它预示你的代码有bug,不过也可能是你的单元测试代码有逻辑错误(注意是逻辑错误)。Errors不是你所期待的,发生了Error你可以按照下面的顺序来检查:

  检查测试所需的环境,如:数据库连接

  检查单元测试代码

  检查你的系统代码

  五、成批运行test case

  这是前面提到的JUnit特性之一。它方便于系统单元测试的成批运行。使用起来也是非常简单,先看下使用代码:

  import junit.framework.Test;

  import junit.framework.TestSuite;

  public class TestAll{

   public static Test suite(){

   TestSuite suite = new TestSuite("TestSuite Test");

   suite.addTestSuite( TestSample.class);

   return suite;

   }

  }

  这个测试程序的编译、运行,和上面TestSample的方式是一样的。

  javac TestAll.java

  java junit.swingui.TestRunner TestAll

  怎么样?这样你在suite方法里面添加几个TestCase就会运行几个,而且它也可以添加TestSuite来将小一点的集合加入大的集合中来,方便了对于不断增加的TestCase的管理和维护。

  你觉得suite方法的作用是不是于java应用程序的main很类似?并且这里的suite必须严格遵守上面的写法!

JUnit和单元测试入门简介

更多精彩请到 http://www.139ya.com

1、几个相关的概念

白盒测试——把测试对象看作一个打开的盒子,程序内部的逻辑结构和其他信息对测试人员是公开的。

回归测试——软件或环境的修复或更正后的“再测试”,自动测试工具对这类测试尤其有用。

单元测试——是最小粒度的测试,以测试某个功能或代码块。一般由程序员来做,因为它需要知道内部程序设计和编码的细节。

JUnit ——是一个开发源代码的Java测试框架,用于编写和运行可重复的测试。他是用于单元测试框架体系xUnit的一个实例(用于java语言)。主要用于白盒测试,回归测试。



2、单元测试概述

2.1、单元测试的好处

A、提高开发速度——测试是以自动化方式执行的,提升了测试代码的执行效率。

B、提高软件代码质量——它使用小版本发布至集成,便于实现人员除错。同时引入重构概念,让代码更干净和富有弹性。

C、提升系统的可信赖度——它是回归测试的一种。支持修复或更正后的“再测试”,可确保代码的正确性。

2.2、单元测试的针对对象

A、面向过程的软件开发针对过程。

B、面向对象的软件开发针对对象。

C、可以做类测试,功能测试,接口测试(最常用于测试类中的方法)。

2.3、单元测试工具和框架

目前的最流行的单元测试工具是xUnit系列框架,常用的根据语言不同分为JUnit(java),CppUnit(C++),DUnit (Delphi ),NUnit(.net),PhpUnit(Php )等等。该测试框架的第一个和最杰出的应用就是由Erich Gamma (《设计模式》的作者)和Kent Beck(XP(Extreme Programming)的创始人 )提供的开放源代码的JUnit。



3.Junit入门简介

3.1、JUnit的好处和JUnit单元测试编写原则

好处:

A、可以使测试代码与产品代码分开。

B、针对某一个类的测试代码通过较少的改动便可以应用于另一个类的测试。

C、易于集成到测试人员的构建过程中,JUnit和Ant的结合可以实施增量开发。

D、JUnit是公开源代码的,可以进行二次开发。

C、可以方便地对JUnit进行扩展。

编写原则:

A、是简化测试的编写,这种简化包括测试框架的学习和实际测试单元的编写。

B、是使测试单元保持持久性。

C、是可以利用既有的测试来编写相关的测试。

3.2、JUnit的特征

A、使用断言方法判断期望值和实际值差异,返回Boolean值。

B、测试驱动设备使用共同的初始化变量或者实例。

C、测试包结构便于组织和集成运行。

D、支持图型交互模式和文本交互模式。

3.3、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期)。

3.4、JUnit的安装和配置

JUnit安装步骤分解:

在http://download.sourceforge.net/junit/中下载JUnit包并将Junit压缩包解压到一个物理目录中(例如C:\Junit3.8.1)。
记录Junit.jar文件所在目录名(例如C:\Junit3.8.1\Junit.jar)。
进入操作系统(以Windows2000操作系统为准),按照次序点击“开始 设置 控制面板”。
在控制面板选项中选择“系统”,点击“环境变量”,在“系统变量”的“变量”列表框中选择“CLASS-PATH”关键字(不区分大小写),如果该关键字不存在则添加。
双击“CLASS-PATH”关键字添加字符串“C:\Junit3.8.1\Junti.jar”(注意,如果已有别的字符串请在该字符串的字符结尾加上分号“;”),这样确定修改后Junit就可以在集成环境中应用了。
对于IDE环境,对于需要用到的JUnit的项目增加到lib中,其设置不同的IDE有不同的设置 。
3.5、JUnit中常用的接口和类

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异常,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()方法返回“失败”状况的简要描述


3.6、JUnit一个实例

在控制台中简单的范例如下:
1、写个待测试的Triangle类,创建一个TestCase的子类ExampleTest:
2、 ExampleTest中写一个或多个测试方法,断言期望的结果(注意:以test作为待测试的方法的开头,这样这些方法可以被自动找到并被测试)
3、 ExampleTest中写一个suite()方法,它会使用反射动态的创建一个包含所有的testXxxx方法的测试套件:
4、 ExampleTest可以写setUp()、tearDown()方法,以便于在测试时初始化或销毁测试所需的所有变量和实例。(不是必须的)

5、写一个main()方法以文本运行器或其它GUI的方式方便的运行测试

6、编译ExampleTest,执行测试。

3.7、Eclipse中JUnit的使用

Eclipse自带了一个JUnit的插件,不用安装就可以在你的项目中开始测试相关的类,并且可以调试你的测试用例和被测试类。

使用步骤如下:

1、新建一个测试用例,点击“File->New->Other…菜单项,在弹出的“New”对话框中选择”Java->JUnit”,下的TestCase 或TestSuite,就进入“New JUnit TestCase”对话框

2、在“New JUnit TestCase”对话框填写相应的栏目,主要有Name(测试用例名),SuperClass(测试的超类一般是默认的 junit.framework.TestCase),Class Under Test(被测试的类),Source Folder(测试用例保存的目录),Package(测试用例包名),及是否自动生成main,setUp,tearDown方法。

3、如果点击下面的”Next>”按钮,你还可以直接勾选你想测试的被测试类的方法,Eclipse将自动生成与被选方法相应的测试方法,点击“Fishish”按钮后一个测试用例就创建好了。

4、编写完成你的测试用例后,点击“Run”按钮就可以看到运行结果了。

3.8、JUnit的扩展应用

以下罗列了些JUnit的扩展应用:

JUnit + HttpUnit=WEB功能测试工具
JUnit + hansel =代码覆盖测试工具
JUnit + abbot =界面自动回放测试工具
JUnit + dbunit =数据库测试工具
JUnit + junitperf=性能测试工具

3.9、一些使用JUnit经验

不要用TestCase的构造函数初始化,而要用setUp()和tearDown()方法。
不要依赖或假定测试运行的顺序,因为JUnit利用Vector保存测试方法。所以不同的平台会按不同的顺序从Vector中取出测试方法。
避免编写有副作用的TestCase。例如:如果随后的测试依赖于某些特定的交易数据,就不要提交交易数据。简单的回滚就可以了。
当继承一个测试类时,记得调用父类的setUp()和tearDown()方法。
将测试代码和工作代码放在一起,一边同步编译和更新。
测试类和测试方法应该有一致的命名方案。如在工作类名前加上test从而形成测试类名。
确保测试与时间无关,不要依赖使用过期的数据进行测试。导致在随后的维护过程中很难重现测试。
如果你编写的软件面向国际市场,编写测试时要考虑国际化的因素。不要仅用母语的Locale进行测试。
尽可能地利用JUnit提供地assert/fail方法以及异常处理的方法,可以使代码更为简洁。
测试要尽可能地小,执行速度快。


参考资料与附件

1. http:// www.junit.org JUnit官方网站

2. http://bbs.51cmm.com 的测试论坛

3. http://www.uml.org.cn 的软件测试专栏

4. 单元测试 《程序员》 2002年7期

5. JUnit设计模式分析 《程序员》2003年6期

6. 《软件测试和JUnit实践》

7. 附件Triangle.java 一个要测试的类

8. 附件ExampleTest.java 一个测试用例类





Triangle.java

/**

* this is Triangle class

* @author liujun

*/

public class Triangle

{

//定义三角形的三边

protected long lborderA = 0;

protected long lborderB = 0;

protected long lborderC = 0;



//构造函数

public Triangle(long lborderA,long lborderB,long lborderC)

{

this.lborderA = lborderA;

this.lborderB = lborderB;

this.lborderC = lborderC;

}

/**

* 判断是否是三角形

* 是返回ture;不是返回false

*/

public boolean isTriangle(Triangle triangle)

{

boolean isTrue = false;

//判断边界,大于0小于200,出界返回false

if((triangle.lborderA>0&&triangle.lborderA<200)

&&(triangle.lborderB>0&&triangle.lborderB<200)

&&(triangle.lborderC>0&&triangle.lborderC<200))

{

//判断两边之和大于第三边

if((triangle.lborderA<(triangle.lborderB+triangle.lborderC))

&&(triangle.lborderB<(triangle.lborderA+triangle.lborderC))

&&(triangle.lborderC<(triangle.lborderA+triangle.lborderB)))

isTrue = true;

}

return isTrue;

}



/**

* 判断三角形类型

* 等腰三角形返回字符串“等腰三角形”;

* 等边三角形返回字符串“等边三角形”;

* 其它三角形返回字符串“不等边三角形”;

*/

public String isType(Triangle triangle)

{

String strType = "";

// 判断是否是三角形

if(this.isTriangle(triangle))

{

//判断是否是等边三角形 if(triangle.lborderA==triangle.lborderB&&triangle.lborderB==triangle.lborderC)

strType = "等边三角形";

//判断是否是不等边三角形

else if((triangle.lborderA!=triangle.lborderB)&&

(triangle.lborderB!=triangle.lborderC)&&

(triangle.lborderA!=triangle.lborderC))

strType = "不等边三角形";

else

strType="等腰三角形";

}

return strType;

}

}



ExampleTest.java

import junit.framework.*;

/**

* Some tests.

*

*/

public class ExampleTest extends TestCase {

public Triangle triangle;

//初始化

protected void setUp() {

triangle=new Triangle(10,2,9);

}



public static Test suite() {

return new TestSuite(ExampleTest.class);

}

//函数isTriangle()的测试用例

public void testIsTriangle() {

assertTrue(triangle.isTriangle(triangle));

}

//函数isType()的测试用例

public void testIsType()

{

assertEquals("这次测试",triangle.isType(triangle),"不等边三角形");

}



//执行测试

public static void main (String[] args) {

//文本方式

junit.textui.TestRunner.run(suite());

//Swingui方式

//junit.swingui.TestRunner.run(suite().getClass());

//awtui方式

//junit.awtui.TestRunner.run(suite().getClass());



}

}