Using JUnit

Junit还是比较简单易用的。

首先,需要导入1个包,就是junit.jar,这个在www.junit.org上应该有下载。我用的是junit3.8.1

另外,还有一个包junit-addons-1.4.jar也很有用。主要是PivateAccessor这个类用处比较大,续后会介绍。我的工程目录(Eclipse3.1)如下:

Using JUnit_第1张图片

注:

测试类的位置没有特殊的要求,不过最好不要和源代码放在一起。但是如果另外建一个包放置测试类的话,在测试的时候就不得不把被测试的类import进来。为了避免这种情况,可以如上图所示建立工程目录,这样,被测试代码和测试代码在2个文件夹中,但是包路径是相同的,也就不用import了。

 

示例用代码(被测试类):

package com.mycompany.junittest;

 

public class Example {

              private int Foo;

             

              public Example(){

                            Foo = 0;

              }

 

              public int getFoo(){

                            return Foo;

              }

             

              private void increment(int i){

                            if (i < 1) {

                                          throw new IllegalArgumentException();

                            }

                            Foo = Foo + i;

              }

}

 

Junit的使用很简单。新建一个类只要使它继承junit.framework.TestCase类就行了。

测试类的命名一般都是 被测试类名+Test

e.g.

 

 

对于public方法的测试:

直接new 一个被测试类的实例,调用该方法就可以了。

 

察看Junit的文档可以看到TestCase类提供了很多assertXXX方法,它们是用来确认测试结果的。根据测试的不同结果,选择不同的assertXXX方法。这一点很容易理解。

另外,比如上面的assertEquals("testIncrement_Success() failed",expected,actual),也可以使用assertEquals(expected,actual)。不过,建议使用前者,并且总是提供一些有用的描述信息,这样不但在测试失败的时候更容易调试,也增加了程序的易读性,易于维护。

 

 

对于private方法的测试:

对于类中的私有成员变量和私有方法,从外部是无法访问的。

对于私有方法的测试,一种方法是声明一个内部类,不过这种方法会使测试代码比较复杂,而且在被测试类被改动的时候,不得不把改动后的类重新拷贝到测试类中。另一种方法就是使用PrivateAccessor类。它的setField(),getField()方法可以设置或取得私有成员变量;invoke()方法可以调用被测试类的私有方法。

 

 

对于异常分支的测试:

有时候方法会抛出异常,需要对这些异常能否在应该抛出的时候抛出进行测试。

如果抛出异常的话,那么程序会跳到catch处,执行其后的语句;assertTrue(true)语句并没有实际的意义,因为它总是会成功执行。之所以在这里添加是为了增加程序的可读性。

Fail()方法的作用是把这个测试fail掉。如果测试代码按照预想的抛出异常的话,就不会执行到fail()语句。当程序没有抛出异常的时候,说明这次测试失败了,必须手动fail掉这次测试,因为Junit并不知道什么样是测试成功,什么样是失败;如果没有fail()语句的话,这次测试会正常完成,但是实际上这次测试是失败的,因为并没有达到要测试异常的目的。

关于setUp()tearDown()

在每个testXXX()方法执行之前Junit都会调用setUp()方法;

在每个testXXX()方法执行之后Junit都会调用tearDown()方法。

这样就保证了不同的测试之间不会相互影响。另外,不要使测试结果之间产生依赖;即不要把一次测试产生的结果,作为另一次测试的条件。这样会增加测试代码的复杂性,而且Junit并不保证所有测试的执行顺序。

附:完整代码

被测试代码:

package com.mycompany.junittest;

public class Example {
 private int Foo;
 
 public Example(){
  Foo = 0;
 }

 public int getFoo(){
  return Foo;
 }
 
 private void increment(int i){
  if (i < 1) {
   throw new IllegalArgumentException();
  }
  Foo = Foo + i;
 }
}

测试代码:

package com.mycompany.junittest;

import junit.framework.TestCase;
import junitx.util.PrivateAccessor;

public class ExampleTest extends TestCase {
 Example ex;
 
 protected void setUp() throws Exception{
  super.setUp();
  ex = new Example();
 }
 
 protected void tearDown() throws Exception{
  super.tearDown();
 }
 
 /*
  * Test public method
  */
 public void testGetFoo() throws Throwable{
  int ret = ex.getFoo();
  int expected = ((Integer)PrivateAccessor.getField(ex,"Foo")).intValue();
  assertEquals("testGetFoo() failed",expected,ret);
 }
 
 /*
  * Test private method
  */
 public void testIncrement_Success() throws Throwable{
  int expected = 1;
  PrivateAccessor.invoke(ex,"increment",new Class[]{int.class},new Object[]{new Integer(expected)});
  int actual = ((Integer)PrivateAccessor.getField(ex,"Foo")).intValue();
  assertEquals("testIncrement_Success() failed",expected,actual);
 }
 
 /*
  * Test exceptions
  */
 public void testIncrement_Exception() throws Throwable{
  try {
   PrivateAccessor.invoke(ex,"increment",new Class[]{int.class},new Object[]{new Integer(0)});
   fail("testIncrement_Exception() failed: IllegalArgumentException not thrown!!!");
  } catch (IllegalArgumentException e) {
   assertTrue(true);
   e.getMessage();
  }
 }
}

 

===============> update on 19th May <==================

package com.company;

import junit.extensions.RepeatedTest;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;

public class RepeatTest extends TestCase {

 protected void setUp() throws Exception {
  super.setUp();
 }

 protected void tearDown() throws Exception {
  super.tearDown();
 }

 public static Test suite(){
  TestSuite suite = new TestSuite();
  TestSuite testSuite = new TestSuite( MoneyTest.class );

//repeat MoneyTest for 10 times
  RepeatedTest repeatedTest = new RepeatedTest(testSuite, 10);
  suite.addTest(repeatedTest);
  return suite;
 }
}


你可能感兴趣的:(Using JUnit)