java的單元測試
1. 概念
java單元測試是最小的功能單元測試代碼, 單元測試就是針對單個java方法的測試
java程序的最小功能單元是方法
2. 單元測試的優點
-
main方法進行測試的缺點:
- 只能有一個main()方法, 不能把測試代碼分離出來
- 無法打印出測試結果和期望結果.例如: expected: 3628800, but actual: 123456
-
單元測試的優點:
- 確保單個方法正常運行
- 如果修改了方法代碼, 只需要保其對應的單元測試通過就可以了
- 測試代碼本省就可以作為示例代碼
- 可以自動化運行所有測試並獲得報告
3. Junit單元測試
JUnit是一個開源的java語言的單元測試框架
專門針對java語言設計, 使用最廣泛, JUnit是標准的單元測試架構
3.1 JUnit特點
- 使用斷言(Assertion)測試期望結果
- 可以方便的組織和運行測試
- 可以方便的查看測試結果
- 常用的開發工具IDEA, Eclipse都集成了JUnit
- 可以方便的繼承到maven中
3.2 maven依賴
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<!-- junit的版本有3.x, 4.x, 5.x 5.x還沒有發布, 現在都用是4.x -->
</dependency>
3.3 在IDE中使用快捷鍵進行單元測試
測試類的使用目錄必須是如下, 測試類規定標准是在test目錄中進行測試
localhost:javatest lingjing$ tree -d -L 3
.
├── src
│ ├── main
│ │ └── java
│ └── test
│ └── java
IDE的快捷鍵是:ctrl+shift+t --> create new test
然后選擇對應的方法進行測試就好了
3.4 斷言
3.4.1 斷言的例子
斷言的使用, 必須先引入必須的包: IDE自動創建的會自動引入
import static org.junit.Assert.*;
例子: 在main包中的編寫的一個正則表達式的類
import java.util.Arrays;
/**
* @ClassName Calculator
* @Description 在main中的主要類
* @Author lingxiangxiang
* @Date 10:07 AM
* @Version 1.0
**/
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;
}
}
測試類:
import org.junit.Test;
import static org.junit.Assert.*;
public class CalculatorTest {
@Test
public void calculate() {
assertEquals(3, new Calculator().calculate("1 + 2"));
assertEquals(3, new Calculator().calculate("1 + 2 + 3"));
}
}
測試類執行結果如下:
1 + 2 => [1 , 2]
1 + 2 + 3 => [1 , 2 , 3]
java.lang.AssertionError:
Expected :3
Actual :6
<Click to see difference>
at javatest.CalculatorTest.calculate(CalculatorTest.java:12)
第一個方法: 1 + 2 => [1 , 2], 最終的結果3是正確的, 所有沒有任何報錯, 正常顯示
第二個方法: 1 + 2 + 3 => [1 , 2 , 3], 最終報錯, 並提示在代碼的位置: CalculatorTest.java:12, 並且羅列出Expected和Actual的值, 清楚的顯示了結果的對比情況, 和代碼出現的位置
3.4.2 斷言的常用方法
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
3.5 使用@Before和@After
- 在@Before方法中初始化測試資源
- 在@After方法中釋放測試資源
- @BeforeClass: 初始化非常耗時的資源, 例如創建數據庫
- @AfterClass: 清理@BeforeClass創建的資源, 例如創建數據庫
3.5.1 對於每一個@Test方法的執行順序
注意:** 單個@Test方法執行前會創建新的XxxTest實例, 實例變量的狀態不會傳遞給下一個@Test方法, 單個@Test方法執行前后會執行@Before和@After方法
-
執行類的構造函數
-
執行@Before方法
-
執行@Test方法
-
執行@After方法
3.5.2 代碼實例:
寫一個整體的測試類如下:
package javatest;
/**
* @ClassName SequenceTest
* @Description TODO
* @Author lingxiangxiang
* @Date 1:54 PM
* @Version 1.0
**/
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()");
}
@Test
public void testC() {
System.out.println(" testC()");
}
}
如果運行整個類, 運行結果如下:
BeforeClass()
new SequenceTest()
Before()
testA()
After()
new SequenceTest()
Before()
testB()
After()
new SequenceTest()
Before()
testC()
After()
AfterClass()
如果運行單個@Test類
BeforeClass()
new SequenceTest()
Before()
testA()
After()
AfterClass()
3.6 異常測試
異常測試可以通過@Test(expected=Exception.class), 對可能發生的每種類型的異常進行測試
- 如果拋出了指定類型的異常, 測試成功
- 如果沒有拋出指定類型的異常, 或者拋出的異常類型不對, 測試失敗
例子:
運行如下代碼: 正常通過
// 運行如下代碼, 正常運行, 確實發生了ArithmeticException異常, 代碼通過
@Test(expected = ArithmeticException.class)
public void testException() {
int i = 1 / 0;
}
運行如下代碼: 有報錯信息
@Test(expected = ArithmeticException.class)
public void testException() {
int i = 1 / 1;
}
執行結果如下:
java.lang.AssertionError: Expected exception: java.lang.ArithmeticException
3.7 參數化測試
@RunWith: 當類被@RunWith注釋修飾, 或者類繼承了一個被該注解類修飾的類, JUnit將會使用這個注解所指明的運行器(runner)來運行測試, 而不是JUni默認的運行器
要進行參數化測試,需要在類上面指定如下的運行器:
@RunWith (Parameterized.class)
然后,在提供數據的方法上加上一個@Parameters注解,這個方法必須是靜態static的,並且返回一個集合Collection。
JUnit4中參數化測試要點:
1. 測試類必須由Parameterized測試運行器修飾
2. 准備數據。數據的准備需要在一個方法中進行,該方法需要滿足一定的要求:
1)該方法必須由Parameters注解修飾
2)該方法必須為public static的
3)該方法必須返回Collection類型
4)該方法的名字不做要求
5)該方法沒有參數
例子:
@RunWith(Parameterized.class)
public class Testa {
@Parameterized.Parameters
public static Collection<?> data() {
return Arrays.asList(new Object[][] { { "1+2", 3 }, { "1+2+5", 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);
}
}
執行結果:
1+2 => [1, 2]
1+2+5 => [1, 2, 5]
123+456 => [123, 456]
1 + 5 + 10 => [ 1 , 5 , 10 ]
3.8 超時測試
@Test(timeout=1000)可以設置超時時間
timeout單位是毫秒