JUnit 4 與 TestNG 對比

付學良的網誌發表於2015-07-14

這兩天在看一本書《Java測試新技術TestNG和高階概念》,作者是 TestNG 的創始人,瞭解了不少關於 TestNG 的知識,看了一篇文章基本把這本書的幾個觀點都體現了,那我就直接翻譯原文就好,省得自己總結。這兩天要不是等原作者的授權的話可能週末本文就釋出了,沒經過人家許可翻譯人家文章應該的確也不是什麼光彩的事情,等等無妨。原文連結JUnit 4 Vs TestNG – Comparison,非常感謝作者寫出好文,不過mkyong先生寫了的確好多文章,經常搜個文章 google 第一篇總是他的。如果有翻譯問題,請拍磚。

————————————————————————————————————————————

Junit 4 和 TestNG 都是 Java 方面非常流行的單元測試框架。在功能上兩個框架都非常類似。到底哪個比較好?在Java專案中我們應該選擇哪個框架?

下圖將會對Junit 4 和 TestNG 做個功能特徵的對比。

JUnit 4 與 TestNG 對比

註解支援

Junit 4 和 TestNG 在註解方面的實現非常相似。

特性 JUnit 4 TestNG
測試註解 @Test @Test
測試套件在執行之前需要執行的 @BeforeSuite
測試套件在執行之後需要執行的 @AfterSuite
在測試之前需要執行的 @BeforeTest
在測試之後需要執行的 @AfterTest
在一個測試方法所屬於的任意一個組的第一個方法被呼叫之前執行 @BeforeGroups
在一個測試方法所屬於的任意一個組的最後一個方法被呼叫之後執行 @AfterGroups
在當前類的第一個測試方法呼叫之前執行 @BeforeClass @BeforeClass
在當前類的最後一個測試方法呼叫之後執行 @AfterClass @AfterClass
每個測試方法之前需要執行 @Before @BeforeMethod
每個測試方法之後需要執行 @After @AfterMethod
忽略 @ignore @Test(enbale=false)
預期異常 @Test(expected = ArithmeticException.class) @Test(expectedExceptions = ArithmeticException.class)
超時 @Test(timeout = 1000) @Test(timeout = 1000)

JUnit 4 和 TestNG 之間註解方面的區別主要有以下幾點:

  1. 在Junit 4 中,如果我們需要在方法前面使用@BeforeClass@AfterClass,那麼該測試方法則必須是靜態方法。TestNG 在方法定義部分則更加的靈活,它不需要類似的約束。
  2. 3個附加的setUp/tearDown級別:套件和分組(@Before/AfterSuite, @Before/AfterTest, @Before/AfterGroup)。想了解詳細的請看這裡

JUnit 4

@BeforeClass
public static void oneTimeSetUp() {
    // one-time initialization code   
	System.out.println("@BeforeClass - oneTimeSetUp");
}

TestNG

@BeforeClass
public void oneTimeSetUp() {
    // one-time initialization code   
	System.out.println("@BeforeClass - oneTimeSetUp");
}

在Junit 4中,註解的命名是比較令人困惑的,例如 BeforeAfter and Expected,我們不是很確切的能理解在方法前面有BeforeAfter這樣的註解是做什麼的,同樣Expected也如此。TestNG在這方面做的就好很多,註解使用了BeforeMethodAfterMethodExpectedException,這樣的名字就非常好理解了。

異常測試

異常測試的意思是在單元測試中應該丟擲什麼異常是合理的,這個特性在兩個框架都已經實現。

JUnit 4

@Test(expected = ArithmeticException.class)  
public void divisionWithException() {  
	int i = 1/0;
}

TestNG

@Test(expectedExceptions = ArithmeticException.class)  
public void divisionWithException() {  
	int i = 1/0;
}

忽略測試

忽略測試意思是在單元測試哪些是可以被忽略的,這個特性在兩個框架都已經實現。

JUnit 4

@Ignore("Not Ready to Run")  
@Test
public void divisionWithException() {  
	System.out.println("Method is not ready yet");
}

TestNG

@Test(enabled=false)
public void divisionWithException() {  
	System.out.println("Method is not ready yet");
}

時間測試

時間測試意思是如果一個單元測試執行的時間超過了一個指定的毫秒數,那麼測試將終止並且標記為失敗的測試,這個特性在兩個框架都已經實現。

JUnit 4

@Test(timeout = 1000)  
public void infinity() {  
	while (true);  
}

TestNG

@Test(timeOut = 1000)  
public void infinity() {  
	while (true);  
}

套件測試

套件測試就是把幾個單元測試組合成一個模組,然後執行,這個特性兩個框架均已實現。然而卻是用了兩個不同的方式來實現的。

JUnit 4

@RunWith 和 @Suite註解被用於執行套件測試。下面的程式碼是所展示的是在JunitTest5被執行之後需要JunitTest1 和 JunitTest2也一起執行。所有的宣告需要在類內部完成。

@RunWith(Suite.class)
@Suite.SuiteClasses({
    JunitTest1.class,
    JunitTest2.class
})
public class JunitTest5 {
}

TestNG

執行套件測試是使用XML檔案配置的方式來做。下面的 XML 的檔案可以使得TestNGTest1TestNGTest2一起執行。

<!DOCTYPE suite SYSTEM "http://beust.com/testng/testng-1.0.dtd" >
<suite name="My test suite">
  <test name="testing">
    <classes>
       <class name="com.fsecure.demo.testng.TestNGTest1" />
       <class name="com.fsecure.demo.testng.TestNGTest2" />
    </classes>
  </test>
</suite>

TestNG可以在這塊做的更好,使用了的概念,每個方法都可以被分配到一個組裡面,可以根據功能特性來分組。例如:

這是一個有4個方法,3個組(method1, method2 和 method4)的類

@Test(groups="method1")
public void testingMethod1() {  
  System.out.println("Method - testingMethod1()");
}  

@Test(groups="method2")
public void testingMethod2() {  
	System.out.println("Method - testingMethod2()");
}  

@Test(groups="method1")
public void testingMethod1_1() {  
	System.out.println("Method - testingMethod1_1()");
}  

@Test(groups="method4")
public void testingMethod4() {  
	System.out.println("Method - testingMethod4()");
}

下面XML檔案定義了一個只是執行methed1的組的單元測試

<!DOCTYPE suite SYSTEM "http://beust.com/testng/testng-1.0.dtd" >
<suite name="My test suite">
  <test name="testing">
  	<groups>
      <run>
        <include name="method1"/>
      </run>
    </groups>
    <classes>
       <class name="com.fsecure.demo.testng.TestNGTest5_2_0" />
    </classes>
  </test>
</suite>

使用分組的概念,整合測試就會更加強大。例如,我們可以只是執行所有測試中的組名為DatabaseFuntion的測試。

引數化測試

引數化測試意思是給單元測試傳多個引數值。這個特性在JUnit 4 和TestNG。然後兩個框架實現的方式卻完全不同。

JUnit 4

@RunWith 和 @Parameter 註解用於為單元測試提供引數值,@Parameters必須返回 List,引數將會被作為引數傳給類的建構函式。

@RunWith(value = Parameterized.class)
public class JunitTest6 {

	 private int number;

	 public JunitTest6(int number) {
	    this.number = number;
	 }

	 @Parameters
	 public static Collection<Object[]> data() {
	   Object[][] data = new Object[][] { { 1 }, { 2 }, { 3 }, { 4 } };
	   return Arrays.asList(data);
	 }

	 @Test
	 public void pushTest() {
	   System.out.println("Parameterized Number is : " + number);
	 }
}

它在使用上有許多的限制;我們必須遵循 JUnit 的方式去宣告引數,引數必須通過建構函式的引數去初始化類的成員來用於測試。返回的引數型別必須是List [],資料已經被限定為String或者是一個原始值。

TestNG

使用XML檔案或者@DataProvider註解來給測試提供引數。

XML檔案配置引數化測試

只是在方法上宣告@Parameters註解,引數的資料將由 TestNG 的 XML 配置檔案提供。這樣做之後,我們可以使用不同的資料集甚至是不同的結果集來重用一個測試用例。另外,甚至是終端使用者,QA 或者 QE 可以提供使用 XML 檔案來提供他們自己的資料來做測試。

Unit Test

public class TestNGTest6_1_0 {

   @Test
   @Parameters(value="number")
   public void parameterIntTest(int number) {
      System.out.println("Parameterized Number is : " + number);
   }

  }

XML 檔案

<!DOCTYPE suite SYSTEM "http://beust.com/testng/testng-1.0.dtd" >
<suite name="My test suite">
  <test name="testing">

    <parameter name="number" value="2"/> 	

    <classes>
       <class name="com.fsecure.demo.testng.TestNGTest6_0" />
    </classes>
  </test>
</suite>

@DataProvider 註解做引數化測試

使用XML檔案初始化資料可以很方便,但是測試偶爾需要複雜的型別,一個String或原始值並不能完全滿足。 TestNG 的@ DataProvider的註解,可以更好的把複雜的引數型別對映到一個測試方法來處理這種情況。

@DataProvider 可以使用 Vector, String 或者 Integer 型別的值作為引數

@Test(dataProvider = "Data-Provider-Function")
public void parameterIntTest(Class clzz, String[] number) {
   System.out.println("Parameterized Number is : " + number[0]);
   System.out.println("Parameterized Number is : " + number[1]);
}

//This function will provide the patameter data
@DataProvider(name = "Data-Provider-Function")
public Object[][] parameterIntTestProvider() {
	return new Object[][]{
	   {Vector.class, new String[] {"java.util.AbstractList", "java.util.AbstractCollection"}},
	   {String.class, new String[] {"1", "2"}},
	   {Integer.class, new String[] {"1", "2"}}
	};
}

@DataProvider 作為物件的引數

P.S “TestNGTest6_3_0” 是一個簡單的物件,使用了get和set方法。

@Test(dataProvider = "Data-Provider-Function")
public void parameterIntTest(TestNGTest6_3_0 clzz) {
   System.out.println("Parameterized Number is : " + clzz.getMsg());
   System.out.println("Parameterized Number is : " + clzz.getNumber());
}

//This function will provide the patameter data
@DataProvider(name = "Data-Provider-Function")
public Object[][] parameterIntTestProvider() {

	TestNGTest6_3_0 obj = new TestNGTest6_3_0();
	obj.setMsg("Hello");
	obj.setNumber(123);

	return new Object[][]{
    	{obj}
	};
}

TestNG的引數化測試使用起來非常的友好和靈活 (不管是XML配置還是在類裡面註解的方式). 它可以使用許多複雜的資料型別作為引數的值,並且沒有什麼限制。如上面的例子所示, we even can pass in our own object (TestNGTest6_3_0) for parameterized test

依賴測試

引數化測試意味著測試的方法是有依賴的,也就是要執行的的方法在執行之前需要執行的部分。如果依賴的方法出現錯誤,所有的子測試都會被忽略,不會被標記為失敗。

JUnit 4

JUnit 框架主要聚焦於測試的隔離,暫時還不支援這個特性。

TestNG

它使用dependOnMethods來實現了依賴測試的功能,如下:

@Test
public void method1() {
   System.out.println("This is method 1");
}

@Test(dependsOnMethods={"method1"})
public void method2() {
	System.out.println("This is method 2");
}

如果method1()成功執行,那麼method2()也將被執行,否則method2()將會被忽略。

討論總結

當我們做完所有特性的對比以後,我建議使用 TestNG 作為 Java 專案的主要單元測試框架,因為 TestNG 在引數化測試、依賴測試以及套件測試(組)方面功能更加強大。TestNG 意味著高階的測試和複雜的整合測試。它更加的靈活,特別是對大的套件測試。另外,TestNG 也涵蓋了 JUnit4 的全部功能。那就沒有任何理由使用 Junit了。

參考資料

TestNG

————

http://en.wikipedia.org/wiki/TestNG

http://www.ibm.com/developerworks/java/library/j-testng/

http://testng.org/doc/index.html

http://beust.com/weblog/

JUnit

———–

http://en.wikipedia.org/wiki/JUnit

http://www.ibm.com/developerworks/java/library/j-junit4.html

http://junit.sourceforge.net/doc/faq/faq.htm

http://www.devx.com/Java/Article/31983/0/page/3

http://ourcraft.wordpress.com/2008/08/27/writing-a-parameterized-junit-test/

TestNG VS JUnit

——————

http://docs.codehaus.org/display/XPR/Migration+to+JUnit4+or+TestNG

http://www.ibm.com/developerworks/java/library/j-cq08296/index.html

http://www.cavdar.net/2008/07/21/junit-4-in-60-seconds/

相關文章