现在的位置: 首页 > 综合 > 正文

JUnit4新特点

2014年01月24日 ⁄ 综合 ⁄ 共 5987字 ⁄ 字号 评论关闭

JUnit 是JAVA语言事实上的标准测试库。JUnit 4是三年以来最具里程碑意义的一次发布。它的新特性主要是针对JAVA5中的标记(annotation)来简化测试,而不是利用子类、反射或命名机制。本文将讲述如何使用JUnit 4,当前提是你最好具有JUnit的使用经验.

JUnit, 由Kent Beck?和 Erich Gamma开发,几乎是JAVA开发最重要的第三方工具。正如Martin Fowler 所说,“在软件开发领域,从来就没有如此少的代码起到了如此重要的作用“。由于JUnit,JAVA代码变得更健壮,更可靠,BUG也比以前更少。由于JUnit (由Smalltalk's的SUnit得来) 的出现,随后产生了许多xUnit的测试工具,如nUnit (.NET), pyUnit (Python), CppUnit (C++), dUnit (Delphi) 和其它不同平台及语言的测试相关的工具。

虽然JUnit也只是一个工具,但其产生的思想和技术却较其架构更意义重大。单元测试,测试先行的编程方式,测试驱动的开发方式,并非必须由JUNIT实现,也不一定要用SWing实现GUI界面。JUNIT最近的一次更新是在三年前,但它比其它大多数有BUG的框架都要健壮,更重要的是,JAVA一直在改进。现在JAVA支持泛型,枚举,可变长度参数,以及标记语言(开创了开发可重用框架的新局面)。

JUnit's的停滞不前使得那些想要变革的开发人员换其它测试工具.挑战者有Bill Venners的Artima SuiteRunner和Cedric Beust的TestNG.这些工具库虽然有值得推荐的功能,但没有任何一款的地位能与JUNIT相比,没有任何一款工具被其它业界产品如Ant, Maven, Eclipse广泛支持.因此Beck 和Gamma双开始利用JAVA5的新特性来开发新版的JUNIT,目的是利用JAVA5中的标记特性使得单元测试开发更容易。Beck说:“JUNIT4的主要目的是通过简化JUNIT的使用鼓励更多的开发人员写更多的测试”。虽然会与以前的版本兼容,但JUNIT4与从JUNIT1.0就开始的版本相比会有一个非常大的变化.

注意: 修改基本框架是一把双刃剑,虽然JUNIT4的目的是清晰的,但细节仍有许多不同,因此本文只是一个简单的介绍,并不是最终文档.

 测试方法

在JUNIT 4中,测试方法由@Test 标记说明,如下:

import org.junit.Test;
import
 junit.framework.TestCase;

public class AdditionTest extends TestCase 
{

  
private int x = 1
;
  
private int y = 1
;
  
  @Test 
  
public void testAddition() 
{
    
int z = x +
 y;
    assertEquals(
2
, z);
  }


}

使用标记的好处是你不用将所有测试方法命名为 testFoo(), testBar()等等以"test"开头的方法。

这种命名机制最大的优点是更适合你的待测试类或方法名称,例如,你可以使用ListTEst.contains()测试 List.contains();使用ListTest.addAll()测试 List.add()等等.

TestCase还可以继续使用,但你没有必须再扩展为子类,只要你声明了@Test,你可以将测试方法放在任何类中,当然如要访问assert等方法,你必须要引用junit.Assert类,如下:

import org.junit.Assert;

public class AdditionTest 
{

  
private int x = 1
;
  
private int y = 1
;
  
  @Test
  
public void addition() 
{
    
int z = x +
 y;
    Assert.assertEquals(
2
, z);
  }


}

你也可以使用JDK5中的新特性(static import)使得跟以前版本一样简单:

import static org.junit.Assert.assertEquals;

public class AdditionTest 
{

  
private int x = 1
;
  
private int y = 1
;
  
  @Test 
  
public void addition() 
{
    
int z = x +
 y;
    assertEquals(
2
, z);
  }


}

这种方法测试受保护的方法非常容易,因为你可以在测试类中继承有受保护方法的类.

SetUp 和TearDown

在JUnit 4中,你仍然可以在每个测试前初始化变量和配置环境,,然而,这些操作可以不用在Setup()中完成,你可以在初始化方法前面添加@Beforer 来表示,如下:

@Before 
protected void initialize() 
{
        
    System.setErr(
new PrintStream(new
 ByteArrayOutputStream()));
        
    inputDir 
= new File("data"
);
    inputDir 
= new File(inputDir, "xslt"
);
    inputDir 
= new File(inputDir, "input"
);
        
}

你也可以有多个方法标记有@Before,所有方法都会在每个测试之前执行。

清除环境与JUNIT3 差不多,在JUNIT3中使用tearDown()方法。在JUnit4中,你还可以使用@After标记来说明:

@After 
protected void disposeDocument() 
{
  doc 
= null
;
  System.gc();   
}

与 @Before一样,你也可以有多个标记有 @After的清除方法,每个都会在执行完每个测试后执行。

最后,你不需要在父类中明确调用这些初始化或清除方法.test runner会自动调用这些标记的方法.子类中的@Before方法在父类的@Before方法之后执行(这与构造函数的执行顺序一样),而@After方法刚好相反,子类中的@After方法先执行.然而,多个@Before和@After方法的执行顺序就是未知的.

测试集范围的初始化

JUnit 4中引入了一项JUNIT3没有的新特性,类级别的setUp()和tearDown(),即在一个类的所有测试前执行初始化,并在所有测试完成后执行清除。

例如,一个测试类中的每个测试都要用到一个数据库连接或网络连接,或其它很耗资源初始化或释放的资源,用不着在每个测试方法前后进行操作,而只需要在测试类开始前后执行即可。下面的示例是使用第三方的库进行错误,在执行所有测试前将错误先重定向到非标准输出,然后在所有测试结束后再输出到需要的地方,这样就不会影响到测试过程中产生的其它信息。

// This class tests a lot of error conditions, which
//
 Xalan annoyingly logs to System.err. This hides System.err 
// before each test and restores it after each test.

private PrintStream systemErr;
    
@BeforeClass 
protected void redirectStderr() 
{
    systemErr 
= System.err; // Hold on to the original value

    System.setErr(new PrintStream(new ByteArrayOutputStream()));
}

    
@AfterClass 
protected void tearDown() {
    
// restore the original value

    System.setErr(systemErr);
}

上面的操作没有必须在每个测试前后执行。然而要注意的是,这种方法可能影响测试间的结果,如果一个测试改变了初始化的对象,而这个对象可能是其它测试的输入,那么测试的结果可能不正确,这种方法将依赖测试的顺序并可能引入BUG。当优化测试性能,并且当你改进了配置和基准测试后而仍然很慢时,如数据库连接或网络问题,你才需要考虑使用这种方法。只有这样,你才能每天执行多次测试。

异常测试

异常测试是JUNIT4中的最大的改进,以前异常测试是通过try catch实现,当抛出异常时,在try的最后添加一条fail()语句实现.如下:

public void testDivisionByZero() {
    
    
try 
{
        
int n = 2 / 0
;
        fail(
"Divided by zero!"
);
    }

    
catch (ArithmeticException success) {
        assertNotNull(success.getMessage());
    }

    
}

这种方法不仅难看,而且造成无论成功或失败,代码覆盖工具都不能执行某些代码.而在JUnit 4中,你可以在要抛出异常的代码中添加标记来声明一个异常是期望的:

@Test(expected=ArithmeticException.class
public void divideByZero() 
{
    
int n = 2 / 0
;
}

如果没有异常抛出,上面的测试则会失败,如果你想知道异常的详细信息或其它情况,你还是要使用try catch才行。

时间测试

性能测试是单元测试中最头疼的问题,JUnit 4也未完全解决此问题, 你可以在JUNIT4的测试方法中添加一个时间参数。如果测试时间超过参数,则测试失败。如下,如果测试时间超过0.5秒,则此测试失败:

@Test(timeout=500
public void retrieveAllElementsInDocument() 
{
    doc.query(
"//*"
);
}
 

新的断言

JUnit 4 增加了两上断文方法用于比较数组:

public static void assertEquals(Object[] expected, Object[] actual)
public static void assertEquals(String message, Object[] expected, Object[] actual)

这两个方法采用最直接方法比较,如果数组长度相同,且每个对应的元素相同,则比较成功,否则不成功.参数为空的情况也作了考虑.

需要补充的地方

JUnit 4是一个非常基本的框架,还不是以前版本的升级。JUNIT3的开发人员会发现有些功能没有。

  • 最大的特点就是没有GUI测试界面,当测试正确时是绿色条,而出错时红色的,你也可以在Eclipse中集成JUNIT使用,但JUNIT4既没有AWT也没有SWING的GUI测试界面;
  • 另一个让人吃惊的是失败(期望错误)和错误(未预计的异常错误)没有明显区别,在JUNIT3中开发人员可以区分这两种情况,而在JUNIT4中不行;
  • 最后一个特点是JUNIT中没有用于建立一堆测试类的suite()方法,取而代之的是,采用变长参数传递未知数量的测试给test runner。

没有GUI测试界面的确不方便,但其它改变简化了JUNIT的使用,从当前JUNIT的操作手册和FAQ的数量就知道,而JUNIT4的文档将不会需要这么多。

资源

抱歉!评论已关闭.