單元測試工具 TestNG 使用

JayChen發表於2019-03-03

本文首發於 jaychen.cc
作者 jaychen

寫一篇小文,介紹一下 Java 下單元測試工具 TestNG 的使用,程式碼在 IDEA 環境在編寫。

單元測試,顧名思義,對系統中原子性的功能進行測試,一般情況下是單元測試是針對某個功能函式的測試。編寫單元測試是系統開發中重要的一環,也是一項科學優雅的裝 X 方式。而且,編寫單元測試程式碼並不是一件很麻煩的事情,只要稍微學習就可以掌握這項技能。

TestNG 使用

快速體驗

在開始之前,需要引入 TestNG 庫,使用 maven 直接引入,在 pom.xml 新增依賴

<dependency>
    <groupId>org.testng</groupId>
    <artifactId>testng</artifactId>
    <version>6.8</version>
    <scope>test</scope>
</dependency>複製程式碼

使用 IDEA 新建一個專案,目錄結構如下:

├── pom.xml
├── src
│   ├── main
│   │   ├── java
│   │   └── resources
│   └── test複製程式碼

新建一個 Demo.java 類,包含如下簡單程式碼

public class Demo {
    public int add(int a, int b) {
        return a + b;
    }

    public int sub(int a, int b) {
        return a - b;
    }
}複製程式碼

在 IDEA 下使用快捷鍵 Ctrl + Shift + t 為其生成測試類

這裡可以看到,我們選擇了 TestNG 作為單元測試庫,IDEA 自動為我們生成了單元測試類的類名,其命名規則為:被測試類+Test。最後勾選要進行測試的方法,這裡我只選擇 add 方法。

確定之後,會在 src/test/java 目錄下生成對應的類檔案,可以看到已經生成了 DemoTest.java 檔案,其內容如下

public class DemoTest {
    @Test
    public void testAdd() throws Exception {

    }
}複製程式碼

此時,我們就可以開始編寫測試程式碼。這裡,單元測試的目的是為了測試 Demo#add 這個函式的功能是否準確正常,所以我們在 testAdd 中編寫程式碼

@Test
public void testAdd() throws Exception {
    Demo d = new Demo();
    assertEquals(7, d.add(3, 4));
}複製程式碼

這裡,使用了 assertEquals 進行斷言,這句話相當於說:d.add(3,4) 的結果應該是 7,你幫我執行下 add 看看是不是返回 7。好了,一個單元測試的用例完成,之後就可以直接執行該測試方法,可以看到輸出如下:

[TestNG] Running:
===============================================
Default Suite
Total tests run: 1, Failures: 0, Skips: 0
===============================================複製程式碼

表明這個測試通過,函式功能沒錯。如果我們把程式碼改成 assertEquals(d.add(3, 4), 8);,那麼就會出現如下提示

Expected :8
Actual   :7
 <Click to see difference>


    at org.testng.Assert.fail(Assert.java:94)
    at org.testng.Assert.failNotEquals(Assert.java:494)
    ...........
===============================================
Default Suite
Total tests run: 1, Failures: 1, Skips: 0
===============================================複製程式碼

表明 add 方法的返回結果和期望的不同,方法可能存在 bug。

這裡要注意一個問題,上面我們對 add 進行一次測試通過,不代表 add 方法就不存在 bug。assertEquals(d.add(3, 4), 7); 只是一個測試用例。這裡要理清一個概念:add 函式編寫了一個單元測試函式 testAdd,之後我們需要使用多個測試用例來測試 add 函式是否存在 bug。為了證明 add 沒有 bug,需要考慮所有可能的情況,包括 輸入為0,輸入的 a,b 引數為負數 等等儘量的覆蓋所有可能性。所以一個嚴謹的測試應該如下:

@Test
public void testAdd() throws Exception {
    Demo d = new Demo();
    assertEquals(d.add(3, 4), 7);
    assertEquals(d.add(-3, 4), 1);
    assertEquals(d.add(-3, -4), -7);
    assertEquals(d.add(0, 4), 4);
    assertEquals(d.add(0, 0), 0);
}複製程式碼

高階用法

上面的例子只是簡單用法,旨在讓初學者可以快速上手瞭解 TestNG 的 用法,下面介紹一些高階用法來幫助我們更好的進行單元測試。

@BeforeClass/@AfterClass@BeforeMethod/@AfterMethod

除了 @Test 註解,TestNG 還有兩對常用的註解:@BeforeClass/@AfterClass@BeforeMethod/@AfterMethod。這些註解的關係如下圖:

從上圖可以看出,@BeforeMethod/@AfterMethod 是在 @Test 註解函式執行之前/之後執行的鉤子函式。在執行每一個 @Test 註解函式執行之前/之後都會執行 @BeforeMethod/@AfterMethod 註解函式。

@BeforeClass/@AfterClass 的作用和 @BeforeMethod/@AfterMethod 類似,不同的是,@BeforeClass/@AfterClass 是在初始化類的時候執行,這就意味著 @BeforeClass/@AfterClass 只會執行一次,而 @BeforeMethod/@AfterMethod 執行次數和 @Test 註解函式個數一樣。

public class DemoTest {

    @BeforeClass
    public static void beforeClass() {
        System.out.println("before test....");
    }

    @BeforeMethod
    public void beforeTest() {
        System.out.println("before  test...");
    }

    @Test
    public void testAdd() {

        int res = new Dao().add(1, 2);
        Assert.assertEquals(res, 3);
    }

    @Test
    public void testSub() {
        int res = new Dao().sub(1, 2);
        Assert.assertEquals(res, -1);
    }

    @AfterMethod
    public void afterTest() {
        System.out.println("after  test....");
    }

    @AfterClass
    public static void afterClass() {
        System.out.println("after class....");
    }
}複製程式碼

執行上面的程式碼,可以看到 beforeClass/afterClass 只執行一次,而 beforeMethod/afterMethod 執行了兩次。

這裡還需要提一點:@BeforeClass/@AfterClass 註解的函式必須使用 static 修飾。

除了使用 assertEquals 斷言函式測試結果之外,TestNG 還提供了一些額外的測試情況。

超時測試

@Test 註解中新增 timeOut 引數就可以進行超時測試,@Test(timeOut=10) 表示測試方法的執行時間應該低於 10ms,如果超時者測試失敗。超時測試對於網路連線類的測試相當有用。超時測試具體用法如下

@Test(timeOut = 1)
public void testSub() {
    int i =0;
    while (i < 1000000000) {
        i++;
    }
}複製程式碼

異常測試

異常測試用於測試方法是否有丟擲異常,通過 @Test(expected=NullPointerException.class) 來指定方法必須丟擲 NullPointerException,如果沒有丟擲異常或者丟擲其他異常則測試失敗。

@Test(expectedExceptions = NullPointerException.class)
public void testSub() {
    throw new  NullPointerException();
}複製程式碼

依賴測試

有時候需要測試方法按照一個特定的順序被呼叫,這個時候需要使用 @Test 註解的 dependsOnMethods 引數來指定依賴方法和方法的執行順序

// test1 執行之前會先執行 test2, test3
@Test(dependsOnMethods = {"test2","test3"})
public void test1(){

}
@Test
public void test2(){

}
@Test
public void test3(){

}複製程式碼

好了,TestNg 的使用就到這裡了,其實單元測試並不是一件麻煩的事情,花上一些時間學習一下很快就很上手。過了 TestNg 下次說下 Mockito 的使用。

相關文章