三里屯摇滚 发表于 2012-02-25 11:55

junit4新特性-测试必备利器

junit4新特性-测试必备利器








Junit4更新的版本很多,现在已经更新到4.10了。发生的变化也相当的明显,为了更好的使用测试,有必要去学习一下其新的功能。
总的来说,其变化还是比较多的。

于是整合,收集了一些网友的文章。综合起来看还是算比较完整了,更多的只有自己去探讨了,不过常用的已经够用。

junit4给我的印像:

1,你的方法不必以test开头命名,你可以在你喜欢的任何地方进行测试,前提是你有@Test在这个方法前注释。

2,加入的很多机制,比如Assumption(假设机制)等等。

3,加入了不少测试方法,比如数组测试,assertEquals(Object[] expected, Object[] actual)

4,套件测试,可以几个类一起进行测试,非常强大。


总之,它更多的是引进的不少注解的方法,比以前方便比如@Ignore可以忽略此方法, @Test(timeout=1)//测试运行时间 (单位:millisecond)

它不是junit3的升级,完全是另外一种版本。




更多详细看看下面的:




一、以下来源于:http://zhan.zhmy.com/archives/2006/79054.html



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的文档将不会需要这么多










二、以下来源于:http://fansofjava.iteye.com/blog/503709


下面列举一些改变之处:
1. 测试由原来的命名模式改变注解,即testXXX变为@Test。其中@Test还提供了额外的属性。如expected,表示期望抛出的异常,用法如下:



Java代码 view plaincopyprint?@Test(expected = NullPointerException.class)   
    public void unsupportedDBCheck() {   
      throw new NullPointerException();   
    }   
    @Test(expected = NullPointerException.class)
      public void unsupportedDBCheck() {
            throw new NullPointerException();
      }由于上面得到期望抛出的异常,所以测试通过。
2. 数组比较改用Assert.assertArrayEquals
3. 套件测试也用注解替换,如下如示:

Java代码 view plaincopyprint?@RunWith(Suite.class)   
@SuiteClasses({   
    Hello.class,   
    TheoryTest.class   
})   
public class SuiteClassesTest {   
   
}   
    @RunWith(Suite.class)
    @SuiteClasses({
      Hello.class,
      TheoryTest.class
    })
    public class SuiteClassesTest {
      
    }4. 通过@Ignore,可以忽略某个方法或整个类的测试
5. 增加了新特性-理论机制(Theory),这个特性听起来很迷惑人,作用是使得开发人员从开始的定义测试用例的阶段就可以通过参数集(理论上是无限个参数)对代码行为进行概括性的总结.开发人员都知道他们代码所想要实现的概括性的总的目的,理论使得他们只需要在一个地方就可以快速的指定这些目的,而不要将这些目的翻译成大量的独立的测试用例。用法如下所示:
Java代码 view plaincopyprint?@RunWith(Theories.class)   
public class TheoryTest {   
   
    @DataPoint public static String name ="theories";   
    @DataPoint public static String password = "2009";   
      
    @Theory   
    public void outNameAndPassword(String name,String password){   
      System.out.println("name="+name+" password="+password);   
    }   
}   
    @RunWith(Theories.class)
    public class TheoryTest {
      
      @DataPoint public static String name ="theories";
      @DataPoint public static String password = "2009";
         
      @Theory
      public void outNameAndPassword(String name,String password){
            System.out.println("name="+name+" password="+password);
      }
    }输出为:


引用

name=theories password=theories
name=theories password=2009
name=2009 password=theories
name=2009 password=2009



也就是说,方法的参数与定义的字段会把所有的组合情况全部考虑进去,虽然用到此特性的地方不多,但有时的确很有用。这样也不用逐个写断言语句,把测试数据集中在一个地方,方便管理。
6. 提供了新的特性-假设机制(Assumption).此特性使用了Hamcrest库的类.本来Hamcrest是一个单独的测试组件,Junit也集成了一部分,但是并没有完全包含。建议使用junit独立的JAR文件,再单独引入hamcrest包。
其实hamcrest的功能相当的强大,理解起来也非常的容易,是一个很不错的组件。不过好像并没发现其参考文档。它提供assertThat,assumeThat,assumeNotNull等假设语句,也提供is,not,both..and,either..or等用法,非常的灵活。如:Java代码 view plaincopyprint?//断言"yy"不等于"xx"   
assertThat("yy", is(not("xx")));   
//abcdefg包含adcd或fsd   
assertThat("abcdefg",anyOf(containsString("abcd"),containsString("fsd")));   
    //断言"yy"不等于"xx"
    assertThat("yy", is(not("xx")));
    //abcdefg包含adcd或fsd
    assertThat("abcdefg",anyOf(containsString("abcd"),containsString("fsd")));其中assumeXXX的目的为,假设此条件成立,才执行后面的语句,否则跳出些测试方法,继续执行其它的测试。如:

Java代码 view plaincopyprint?//如果此假设语句不成立,则不会打印出this is assumeAssume.assumeThat(4,both(lessThanOrEqualTo(6)).and(greaterThan(3)));   
System.out.println("this is assume");   
    //如果此假设语句不成立,则不会打印出this is assume
    Assume.assumeThat(4,both(lessThanOrEqualTo(6)).and(greaterThan(3)));
    System.out.println("this is assume");7. @Before,@After,@BeforeClass,@AfterClass.这几个注解一看便知大概,@Before表示每个测试方法执行前执行一次,而@BeforeClass表示整个类测试前执行一次。不过需要注意的是,@BeforeClass,@AtferClass注解的方法必须是静态的。

8. Junit提供了新的核心运行类MaxCore,相对于以前的JunitCore运行机制,这个类有一系列的优点,如从未测试过的方法优先测试,剩下的测试中,以前测试失败的方法优先测试,再其次,运行快的优先于运行慢的方法。用法如官方例子如示:
Java代码 view plaincopyprint?public static class TwoUnEqualTests {   
    @Test   
    public void slow() throws InterruptedException {   
      Thread.sleep(100);   
      fail();   
    }   
    @Test   
    public void fast() {   
      fail();   
    }   
}   
   
@Test   
public void rememberOldRuns() {   
    File maxFile = new File("history.max");   
    MaxCore firstMax = MaxCore.storedLocally(maxFile);   
    firstMax.run(TwoUnEqualTests.class);   
   
    MaxCore useHistory= MaxCore.storedLocally(maxFile);   
    List<Failure> failures= useHistory.run(TwoUnEqualTests.class)   
            .getFailures();   
    assertEquals("fast", failures.get(0).getDescription().getMethodName());   
    assertEquals("slow", failures.get(1).getDescription().getMethodName());   
}   
    public static class TwoUnEqualTests {
      @Test
      public void slow() throws InterruptedException {
            Thread.sleep(100);
            fail();
      }
      @Test
      public void fast() {
            fail();
      }
    }
      
    @Test
    public void rememberOldRuns() {
      File maxFile = new File("history.max");
      MaxCore firstMax = MaxCore.storedLocally(maxFile);
      firstMax.run(TwoUnEqualTests.class);
      
      MaxCore useHistory= MaxCore.storedLocally(maxFile);
      List<Failure> failures= useHistory.run(TwoUnEqualTests.class)
                .getFailures();
      assertEquals("fast", failures.get(0).getDescription().getMethodName());
      assertEquals("slow", failures.get(1).getDescription().getMethodName());
    }当然这个替代也是相对的,有时候还是可以继续用JUnitCore,MaxCore只是在JUnitCore基础上增加优先测试之类的规则,但是有些功能还是需要用JUnitCore。比如说,如果想在eclipse中不通过junit插件来运行单元测试,就需要JUnitCore:
Java代码 view plaincopyprint?public class ObjectToClassTest {
    @Test   
    public void ObjectTest(){   
      int[] a={1,2};   
      int[] b={1,2};   
      Assert.assertArrayEquals(a,b);   
    }   
    public static void main(String[] args){   
      JUnitCore.main("com.junit.ObjectToClassTest");   
    }   
}   
    public class ObjectToClassTest {
      
      @Test
      public void ObjectTest(){
            int[] a={1,2};
            int[] b={1,2};
            Assert.assertArrayEquals(a,b);
      }
      public static void main(String[] args){
            JUnitCore.main("com.junit.ObjectToClassTest");
      }
    }当然这种方式针对的是类,不能限制到方法上,如果有多个类,只需要用空格把类隔开即可。

上面基本包含了Junit4.6之前的新特性,至于以后的新特性,会花专门的篇幅来讲解。







阳光的扣子 发表于 2012-02-25 11:55

谢谢分享
页: [1]
查看完整版本: junit4新特性-测试必备利器