> 本章介紹 JUnit4 的最佳實踐,常用注解以及運行流程
1. 完善代碼——JUnit最佳實踐
```java
package com.dodoke;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
/**
* 計算器測試類
*/
public class CalculatorTest {
private Calculator calculator;
// 執行測試方法之前調用,初始化計算器類實例
@Before
public void setUp() throws Exception {
calculator = new Calculator();
}
// 測試加法
@Test
public void testSum() throws Exception {
long result = calculator.sum(10, 3);
Assert.assertEquals(13L, result);
}
// 測試減法
@Test
public void testSubtract() throws Exception {
long result = calculator.subtract(10, 3);
Assert.assertEquals(7L, result);
}
// 測試乘法
@Test
public void testMultiply() throws Exception {
long result = calculator.multiply(10, 3);
Assert.assertEquals(30L, result);
}
// 測試除法
@Test
public void testDivide() throws Exception {
double result = calculator.divide(10, 2);
Assert.assertEquals(10 / 2, result, 1E-10);
}
}
```
- 測試方法上必須使用 @Test 注解修飾
- 測試方法必須使用 public void 進行修飾,不能帶任何的參數
- 新建一個源代碼目錄來存放我們的測試代碼,即將測試代碼和項目業務代碼分開
- 測試類所在的包名應該和被測試類所在的包名保持一致
- 測試單元中的每個方法必須可以獨立測試,測試方法間不能有任何的依賴
- 測試類使用 Test 作為類名的后綴(不是必須)
- 測試方法使用 test 作為方法名的前綴(不是必須)
2. 測試失敗的兩種情況
- 測試用例不是用來證明你是對的,而是用來證明你沒有錯。
- 測試用例用來達到想要的預期結果,但對于邏輯錯誤無能為力。
- Failure: 一般有單元測試使用的斷言方法判斷失敗所引起的。這僅僅表示測試點發現了問題,就是說程序輸出結果和我們預期的不一樣。
- Error: 是由代碼異常引起的,它可以產生于測試代碼本身的錯誤,也可以是被測試代碼中的bug。
```java
package com.dodoke;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
/**
* 錯誤和失敗測試類
*/
public class ErrorAndFailureTest {
private Calculator calculator;
@Before
public void setUp() throws Exception {
calculator = new Calculator();
}
@Test
public void testDivide() throws Exception {
Assert.assertEquals(10.0 / 3, calculator.divide(10, 3), 1E-10);
// Assert.assertEquals(10.0 / 0, calculator.divide(10, 0), 1E-10);
}
}
```
```
// 運行結果 1
java.lang.AssertionError:
Expected :3.3333333333333335
Actual :3.0
```
```
// 運行結果 2
java.lang.ArithmeticException: by zero
```
3. JUnit運行流程
- @BeforeClass: 修飾的方法必須要是靜態方法,會在所有方法被調用前被執行,當測試類被加載后接著就會運行它,而且在內存中它只會存在一份實例,它比較適合加載配置文件。
- @AfterClass: 修飾的方法必須要是靜態方法,會在所有測試結束之后運行,通常會用來對資源的清理,如關閉數據庫的連接。
- @Before: 每一個測試方法之前運行
- @After: 每一個測試方法之后運行
```java
package com.dodoke;
import org.junit.*;
/**
* JUnit流程測試類
*/
public class JUnitFlowTest {
@BeforeClass
public static void testBeforeClass() throws Exception {
System.out.println("BeforeClass");
}
@AfterClass
public static void testAfterClass() throws Exception {
System.out.println("AfterClass");
}
@Before
public void testBefore() throws Exception {
System.out.println("Before");
}
@After
public void testAfter() throws Exception {
System.out.println("After");
}
@Test
public void testTest() throws Exception {
System.out.println("Test");
}
}
```
```
BeforeClass
Before
Test
After
AfterClass
```
4. JUnit常用注解
- @Test: 將一個普通的方法修飾成為一個測試方法
- @Test(expected=XXException.class) 預期異常
- @Test(timeout=xx(毫秒)) 耗費時間
- @BeforeClass: 它會在所有的方法運行前被執行,static修飾
- @AfterClass: 它會在所有的方法運行后被執行,static修飾
- @Before: 會在每一個測試方法被運行前執行一次
- @After: 會在每一個測試方法運行后執行一次
- @Ignore: 所修飾的方法會被測試運行器忽略
- @RunWith: 可以更改測試運行器 org.junit.runner.Runner
```java
@Test(expected = ArithmeticException.class)
public void testExpected() throws Exception {
double result = new Calculator().divide(10, 0);
Assert.assertEquals(10.0 / 3, result, 1E-10);
}
@Test(timeout = 1)
public void testTimeout() throws Exception {
long result = new Calculator().sum(10, 3);
Assert.assertEquals(13L, result);
}
@Ignore
public void testIgnore() throws Exception {
System.out.println("Ignore");
}
```
```
// testTimeout 測試結果
org.junit.runners.model.TestTimedOutException: test timed out after 1 milliseconds
```