JUnit 4 與 TestNG 對比
這兩天在看一本書《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 |
測試註解 | @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 之間註解方面的區別主要有以下幾點:
- 在Junit 4 中,如果我們需要在方法前面使用
@BeforeClass
和@AfterClass
,那麼該測試方法則必須是靜態方法。TestNG 在方法定義部分則更加的靈活,它不需要類似的約束。 - 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中,註解的命名是比較令人困惑的,例如 Before
, After
and Expected
,我們不是很確切的能理解在方法前面有Before
和After
這樣的註解是做什麼的,同樣Expected
也如此。TestNG在這方面做的就好很多,註解使用了BeforeMethod
,AfterMethod
和ExpectedException
,這樣的名字就非常好理解了。
異常測試
異常測試的意思是在單元測試中應該丟擲什麼異常是合理的,這個特性在兩個框架都已經實現。
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 的檔案可以使得TestNGTest1
和TestNGTest2
一起執行。
<!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
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/
相關文章
- junit5 是不是全方面吊打 testng
- Spring 對 Junit4,Junit5 的支援上的運用Spring
- JUnit4.8.2原始碼分析-4 RunNotifier與RunListener原始碼
- Junit 4 測試方法
- JUnit4教程+實踐
- JUnit4小白入門
- Python==與is對比Python
- 使用Junit 5時,如何同時使用 junit4和 PowerMockMock
- Kotlin 與 Java 對比KotlinJava
- pyppeteer與selenium對比
- 對比Riak與HbaseOS
- redis與rabbitmq對比RedisMQ
- synchronized 與 Lock 的對比synchronized
- Terraform與其他工具對比ORM
- openGauss 對比-磁碟與MOT
- Junit5系列-Junit5中assertThrows()與assertDoesNotThrow()方法詳解
- Go 與 C++ 的對比和比較GoC++
- Flutter 與 iOS 原生 WebView 對比FlutteriOSWebView
- Flutter 與 Android 原生 WebView 對比FlutterAndroidWebView
- Mobx 與 Redux 的效能對比Redux
- 客觀對比Node 與 GolangGolang
- ListView 與 RecyclerView 簡單對比View
- 對比ubuntu與centos系統 UbuntuCentOS
- ubuntu與centos系統對比UbuntuCentOS
- RabbitMQ與Kafka選型對比MQKafka
- XML 與 JSON 優劣對比XMLJSON
- HarmonyOS與Android的全面對比Android
- Linux容器與Docker的對比LinuxDocker
- MySQL 半同步 與Raft對比MySqlRaft
- TDSQL-A與CK的對比SQL
- Servlet與Netty橫向對比ServletNetty
- OSI與TCP/IP的對比TCP
- 五年了,你還在用Junit4嗎?
- Beyond Compare 4 for Mac,檔案對比同步工具Mac
- jwt 實踐以及與 session 對比JWTSession
- Hyperf 與 Lumen 的壓測比對
- Spark與MapReduce的對比(區別)Spark
- Ansj與hanlp分詞工具對比HanLP分詞
- ClickHouse與ES的優劣對比