單元測試框架 TestNG 和 Junit4的區別

在自動化測試時,經常會用到TestNg 或 Junit 測試框架。那麼它們之間有什麼聯繫和區別,如何使用呢?在面試過程中也會經常被問到,結合網上一的些文章,做了以下總結。

TestNg主要用於單元測試和集成測試,它涵蓋了 JUnit4 的全部功能,並且在參數化測試、依賴測試以及套件測試(組)方面功能上更加強大。那麼TestNg與Junit4具體有哪些區別呢?

下面表中概括了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)

1.在Junit 4 中,在方法上使用@BeforeClass和@AfterClass時,那麼該測試方法則必須是靜態方法。TestNG 被@BeforeClass 和@AfterClass註釋的方法可以不寫成static方法。


2. 在JUnit 4中,註釋命名約定有點混亂,例如“Before”,“After”和“Expected”,我們並不真正瞭解“Before”和“After”之前的內容,以及要測試中的“預期” 方法。TestiNG更容易理解,它使用類似“BeforeMethod”,“AfterMethod”和“ExpectedException”就很明瞭。

3.Junit4做忽略測試時,用的是@Ingore,而TestNG則是在@Test註解上添加參數,如:@Test(enabled = false)

4.“超時測試”表示如果單元測試所花費的時間超過指定的毫秒數,則測試將會終止,並將其標記爲失敗,此功能在JUnit 4和TestNG中均可實現。

Junit4做超時測試時,使用如:@Test(timeout=100)其中o是小寫。而TestNG使用如:@Test(timeOut=100)其中O是小寫

 

5.“異常測試”是指從單元測試中拋出的異常。

Junit4做異常測試時,使用如:@Test(expected = ArithmeticException.class) 。

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

而TestNg使用如:@Test(expectedExceptions = ArithmeticException.class) 

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

6.套件測試(幾個單元測試案例,組合成一個模塊,再運行)

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>
       <classname="com.fsecure.demo.testng.TestNGTest1"/>
       <classname="com.fsecure.demo.testng.TestNGTest2"/>
    </classes>
  </test>
</suite>

TestNG使用了組的概念,每個方法都可以被分配到一個組裏面,可以根據功能特性來分組。

捆綁幾個單元測試並一起運行. 下面是一個有四個方法的類,三個組(A1,A2和A3)

public class TestNgGroups {
    @Test(groups = "A1")
    public void test1(){
        System.out.println("this is test1 ---------------");
    }
    @Test(groups = "A2")
    public void test2(){
        System.out.println("this is test2 ---------------");
    }
    @Test(groups = "A1")
    public void test3(){
        System.out.println("this is test3 ---------------");
    }
    @Test(groups = "A3")
    public void test4(){
        System.out.println("this is test4 ---------------");
    }
}

下面XML文件定義了一個只是執行A1的組的單元測試:

<?xml version="1.0" encoding="utf-8" ?>
<suite name="testproj" parallel="false">
    <test name="testDemo1">
        <groups>
            <run>
                <include name="A1"/>
            </run>
        </groups>
     <classes>
         <class name="testng.TestNgGroups"></class>
     </classes>
    </test>
</suite>

7.參數化測試(即給單元測試用例傳多個參數值)

JUnit 4中使用@RunWith 和 @Parameter 註解用於爲單元測試提供參數值,@Parameters必須返回 List,參數將會被作爲參數傳給類的構造函數。它在使用上有許多的限制;使用時必須遵循 JUnit 的方式去聲明參數,參數必須通過構造函數的參數去初始化類的成員來用於測試。返回的參數類型必須是List [],數據已經被限定爲String或者是一個原始值。

@RunWith(value = Parameterized.class)
publicclassJunitTest6 {
 
     privateintnumber;
 
     publicJunitTest6(intnumber) {
        this.number = number;
     }
 
     @Parameters
     publicstaticCollection<Object[]> data() {
       Object[][] data = newObject[][] { { 1}, { 2}, { 3}, { 4} };
       returnArrays.asList(data);
     }
 
     @Test
     publicvoidpushTest() {
       System.out.println("Parameterized Number is : "+ number);
     }
}

 

TestNG使用XML文件或者@DataProvider註解來給測試提供參數。
1)、XML文件配置參數化測試時,只需要在方法上聲明@Parameters註解,參數的數據將由 TestNG 的 XML 配置文件提供。之後,就可以使用不同的數據集甚至是不同的結果集來重用一個測試用例。

@Parameters({"param1"})
@Test
public void paramterTest(String param1){
    System.out.println("\n---------------"+param1);
}

XML 文件

<?xml version="1.0" encoding="utf-8" ?>
<suite name="testngpro" parallel="tests" thread-count="1">
    <parameter name="param1" value="http://127.0.0.1:4723/wd/hub" />
    <test name="testDemo1">
     <classes>
         <class name="testng.TestNgDataprovider"></class>
     </classes>
    </test>
</suite>

注意:直接運行TestNgDataprovider類,會報錯(如下)。需要運行testng.xml纔可以。

Parameter &apos;param1&apos; is required by @Test on method paramterTest but has not been marked @Optional or defined
in C:\Users\ccc\.IntelliJIdea2017.3\system\temp-testng-customsuite.xml
    at org.testng.internal.Parameters.createParams(Parameters.java:290)
    at org.testng.internal.Parameters.createParametersForMethod(Parameters.java:359)
    at org.testng.internal.Parameters.createParameters(Parameters.java:620)
    at org.testng.internal.Parameters.handleParameters(Parameters.java:769)
    at org.testng.internal.ParameterHandler.handleParameters(ParameterHandler.java:49)
    at org.testng.internal.ParameterHandler.createParameters(ParameterHandler.java:37)
    at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:914)
    at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:125)
    at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:109)
    at org.testng.TestRunner.privateRun(TestRunner.java:648)
    at org.testng.TestRunner.run(TestRunner.java:505)
    at org.testng.SuiteRunner.runTest(SuiteRunner.java:455)
    at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:450)
    at org.testng.SuiteRunner.privateRun(SuiteRunner.java:415)
    at org.testng.SuiteRunner.run(SuiteRunner.java:364)
    at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
    at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:84)
    at org.testng.TestNG.runSuitesSequentially(TestNG.java:1187)
    at org.testng.TestNG.runSuitesLocally(TestNG.java:1116)
    at org.testng.TestNG.runSuites(TestNG.java:1028)
    at org.testng.TestNG.run(TestNG.java:996)
    at org.testng.IDEARemoteTestNG.run(IDEARemoteTestNG.java:72)
    at org.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:123)

 2)、@DataProvider 註解做參數化測試
@ DataProvider的註解,可以更好的把複雜的參數類型映射到一個測試方法上
@DataProvider 可以使用 Vector, String 或者 Integer 類型的值作爲參數

public class TestNgDataprovider {
    @Test(dataProvider = "userData")
    public void test(Class clazz, String[] str) {
        System.out.println(clazz + "-------------" + str[0]);
        System.out.println(clazz + "-------------" + str[1]);
    }

    @DataProvider(name = "userData")
    public Object[][] data() {
        Object[][] objects = new Object[][]{
                {Vector.class, new String[]{"java.util.Arrays", "java.util.List"}},
                {String.class, new String[]{"this is my str", "this is my pp"}},
                {Integer.class, new String[]{"123", "345"}},
                {Float.class, new String[]{"12.45f", "33.11f"}}};
        return objects;
    }
}

輸出: 

class java.util.Vector-------------java.util.Arrays
class java.util.Vector-------------java.util.List
class java.lang.String-------------this is my str
class java.lang.String-------------this is my pp
class java.lang.Integer-------------123
class java.lang.Integer-------------345
class java.lang.Float-------------12.45f
class java.lang.Float-------------33.11f

@DataProvider 作爲對象的參數

@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 = newTestNGTest6_3_0();
    obj.setMsg("Hello");
    obj.setNumber(123);
 
    returnnewObject[][]{
        {obj}
    };
}

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

JUnit4 框架主要聚焦於測試的隔離,暫時還不支持這個特性。TestNG使用dependOnMethods、dependsOnGroups 來實現了依賴測試的功能。

依賴測試方法:如果method1()成功執行,那麼method2()也將被執行,否則method2()將會被忽略。

@Test
public  void  method1() {
   System.out.println("This is method 1");
}
 
@Test(dependsOnMethods={"method1"})
public void  method2() {
    System.out.println("This is method 2");
}
依賴羣組:
    @Test(groups = { "init.1" })
    public void test1() {
    }
    @Test(groups = { "init.2" })
    public void test2() {
    }
    @Test(dependsOnGroups = { "init.*" })
    public void test2() { 
    }

9、併發測試
Junit單元測試不支持多線程測試,TestNg使用threadPoolSize用來指明線程池的大小。
以下例子,併發數爲5,可用線程數3。

public class TestNgThreadPoolSize {
    @Test(threadPoolSize = 3,invocationCount = 5)
    public void threadPool(){
        System.out.println("Thread ----------"+Thread.currentThread().getName());
    }
}

輸出:

Thread ----------TestNG-methods-3
Thread ----------TestNG-methods-2
Thread ----------TestNG-methods-2
Thread ----------TestNG-methods-3
Thread ----------TestNG-methods-1

使用testng配置文件併發測試
1)、Parallel=”methods”的意思是指TestNG會將method作爲併發的元子單位,即每個method運行在自己的thread中

public class TestNgThreadPoolSize1 {
    @Test
    public void threadPool_A(){
        System.out.println();
        System.out.println("Thread A----------"+Thread.currentThread().getId());
    }
    @Test
    public void threadPool_B(){
        System.out.println("Thread B----------"+Thread.currentThread().getId());
    }
    @Test
    public void threadPool_C(){
        System.out.println("Thread C----------"+Thread.currentThread().getId());
    }
    @Test
    public void threadPool_D(){
        System.out.println("Thread D----------"+Thread.currentThread().getId());
    }
    @Test
    public void threadPool_E(){
        System.out.println("Thread E----------"+Thread.currentThread().getId());
    }
}

testng.xml配置:

<?xml version="1.0" encoding="utf-8" ?>
<suite name="testngpro" parallel="methods" thread-count="2">
    <parameter name="param1" value="http://127.0.0.1:4723/wd/hub" />
    <test name="testDemo1">
     <classes>
         <class name="testng.TestNgThreadPoolSize1"></class>
     </classes>
    </test>
</suite>

 因爲parallel=”methods”,所以每個method都有自己的thread,故輸出:

Thread A----------1
Thread B----------1
Thread C----------1
Thread D----------1
Thread E----------1

2)、parallel=”tests”,則指會將test 作爲併發的元子單位 

總結

在考慮所有功能比較之後,建議使用TestNG作爲Java項目的核心單元測試框架,因爲TestNG在參數化測試,依賴測試和套件測試(分組概念)方面更加突出。 TestNG用於高級測試和複雜集成測試。 它的靈活性對於大型測試套件尤其有用。 此外,TestNG還涵蓋了整個核心的JUnit4功能。這樣說來,好像也沒有理由使用JUnit了。

部分參考文章:https://blog.csdn.net/chuoyuetang3940/article/details/101032627

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章