Java單元測試框架JUnit的基本使用
單元測試十分重要!尤其是微服務web之類的複雜項目,這類項目代碼的嵌套層次多,方法層數多,如果不做單元測試,功能完成之後bug的數量級肯定會很大。如果你有非常嚴格的單元測試,每寫一個方法,每完成一模塊或者功能,都進行了單元測試,那麼在業務功能整體完成之後,你就會發現你基本不可能出現bug。單元測試的好處非常多,還可以極大的減少程序後期的維護成本和工作量。有了成套的單元測試,後期改代碼排查問題,你就不用一遍一遍的讀代碼了,直接跑一遍單元測試就知道大概了。
文章目錄
1. 安裝使用
maven配置,簡單而俗套
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
2. 實例待測試代碼
一個別人寫好的計算類,做實例用的,參考價值還可以,拿來直接用。
public class Calculator {
public int calculate(String expression) {
String[] ss = expression.split("\\+");
System.out.println(expression + " => " + Arrays.toString(ss));
int sum = 0;
for (String s: ss) {
sum += Integer.parseInt(s.trim());
}
return sum;
}
}
3. 編寫測試類
大體的結構基本在創建項目的時候,Maven原型已經給你創建好了,具體的細節目錄和包結構因人而異,可以隨意發揮。
import org.junit.Test;
import static org.junit.Assert.*;
public class CalculatorTest {
@Test
public void calculate() {
assertEquals(4, new Calculator().calculate("1 + 2"));
assertEquals(6, new Calculator().calculate("1 + 2 + 3"));
}
}
4. 常用的斷言方法
- assertEquals(100, x): 斷言相等
- assertArrayEquals({1, 2, 3}, x): 斷言數組相等
- assertEquals(3.1416, x, 0.0001): 浮點數組斷言相等
- assertNull(x): 斷言爲null
- assertTrue(x > 0): 斷言爲true
- assertFalse(x < 0): 斷言爲false;
- assertNotEquals: 斷言不相等
- assertNotNull: 斷言不爲null
5. 單元測試邏輯結構
- 在@Before方法中初始化測試資源
- 在@After方法中釋放測試資源
- @BeforeClass: 初始化非常耗時的資源, 例如創建數據庫
- @AfterClass: 清理@BeforeClass創建的資源, 例如創建數據庫
- 對於每一個@Test方法的執行順序
- 單個@Test方法執行前會創建新的XxxTest實例, 實例變量的狀態不會傳遞給下一個@Test方法,
- 單個@Test方法執行前後會執行@Before和@After方法
- 執行順序
- 執行類的構造函數=>執行@Before方法=>執行@Test方法=>執行@After方法
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
public class SequenceTest {
@BeforeClass
public static void setUpBeforeClass() throws Exception {
System.out.println("BeforeClass()");
}
@AfterClass
public static void tearDownAfterClass() throws Exception {
System.out.println("AfterClass()");
}
@Before
public void setUp() throws Exception {
System.out.println(" Before()");
}
@After
public void tearDown() throws Exception {
System.out.println(" After()");
}
public SequenceTest() {
System.out.println(" new SequenceTest()");
}
@Test
public void testA() {
System.out.println(" testA()");
}
@Test
public void testB() {
System.out.println(" testB()");
}
}
6. 參數化測試
@RunWith: 當類被@RunWith註釋修飾, 或者類繼承了一個被該註解類修飾的類, JUnit將會使用這個註解所指明的運行器(runner)來運行測試, 而不是JUni默認的運行器
要進行參數化測試,需要在類上面指定如下的運行器:@RunWith (Parameterized.class)
然後,在提供數據的方法上加上一個@Parameters註解,這個方法必須是靜態static的,並且返回一個集合Collection。
具體詳細說明如下:
- 測試類必須由Parameterized測試運行器修飾
- 準備數據。數據的準備需要在一個方法中進行,該方法需要滿足一定的要求:
- 該方法必須由Parameters註解修飾
- 該方法必須爲public static的
- 該方法必須返回Collection類型
- 該方法的名字不做要求
- 該方法沒有參數
@RunWith(Parameterized.class)
public class TestParams {
@Parameterized.Parameters
public static Collection<?> data() {
return Arrays.asList(new Object[][] { { "1+2", 3 }, { "1+2+3", 8 }, { "123+456", 579 }, { " 1 + 5 + 10 ", 16 } });
}
Calculator calc;
@Parameterized.Parameter(0)
public String input;
@Parameterized.Parameter(1)
public int expected;
@Before
public void setUp() {
calc = new Calculator();
}
@Test
public void testCalculate() {
int r = calc.calculate(this.input);
assertEquals(this.expected, r);
}
}
7. 其他常用測試
7.1 異常測試
異常測試可以通過@Test(expected=Exception.class), 對可能發生的每種類型的異常進行測試
- 如果拋出了指定類型的異常, 測試成功
- 如果沒有拋出指定類型的異常, 或者拋出的異常類型不對, 測試失敗
// 發生了ArithmeticException異常, 代碼通過
@Test(expected = ArithmeticException.class)
public void testException() {
int i = 1 / 0;
}
7.1 超時設置
在測試類的方法上使用 @Timeout 註解,測試類的所有方法應用 Timeout 規則
@Test(timeout=1000)可以設置超時時間,單位是毫秒
@Timeout 註解來測試任意特定方法的執行時間。如果測試方法的執行時間大於指定的超時參數,測試方法將拋出異常,測試結果爲失敗。指定的超時參數是以毫秒記。
mport org.junit.*;
public class TimeOutTest {
@Test(timeout = 1000)
public void infinity() {
while (true);
}
}