本文首發於 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 的使用。