Java 單元測試:
單元測試是開發者編寫的一小段代碼,用於檢測被測代碼的一個很小的、很明確的功能是否正確。
單元測試的方法:
人工靜態分析:人工閱讀檢測代碼
自動靜態分析:使用代碼復查工具檢查
自動動態測試:用工具自動生成測試用例並執行被測程序
人工動態測試:人工設定程序的輸入和預期輸出,執行程序。
Junit 單元測試:
它是人工動態測試
支持語言C++、Java,支持的IDE: Eclipse
功能:用單獨的classloader來運行每個單元測試
標准的資源初始化和回收方式(setUp、tearDown)
Eclipse 使用Junit測試的方法
1、導入 Junit Jar包,可以在Java Build Path 中添加,最好直接使用Eclipse 自帶的JUnit套件
2、為單元測試代碼創建單獨的目錄,單元測試代碼和被測試代碼建議使用一樣的包層結構。比如src\com\lls\Person.java 和 testSrc\com\lls\PersonTest.java
3、創建單元測試類,可以直接通過Eclipse的Junit Test Case 功能進行添加,這樣就只需修改Source folder即可
下面內容為Junit 4.0之后內容
4、Junix 包所定義的注解及其意義
方法注解
@Before - 它所修飾的方法在每個測試方法執行之前都要執行一次。 之前沒有注解的版本叫做setUp方法
@After - 它所修飾的方法在每個測試方法執行之后都要執行一次。 tearDown方法
@Test - 測試用的方法,他可以添加參數來對特定的情況進行驗證
比如@Test(expected=*.class) 表示的是異常的類型,如果沒有產生異常則失敗
@Test(timeout = xxx) 表示的是測試的最大時間,超時則認為失敗
@ignore - 它所修飾的測試方法會被忽略
其中@Before 和@After 被稱為Fixture,也就是每個測試之前都必須要執行的內容
5、測試方法使用要求
@Test
public void xxx(無參)
6、使用Eclipse的 Run as Juit來執行測試用例
如果與測試結果不符,則結果為 失敗 failure
如果測試時,直接產生異常,則結果為error
7、測試套件
也就是一次執行多個測試用例
方法:創建一個空類作為測試套件的入口。使用注解RunWith和SuiteClasses修飾這個空類。
將org.junit.runners.Suite 作為參數傳入注解RunWith,表示使用套件運行器執行。
將測試類組成數組作為注解SuiteClasses的參數
比如:
@RunWith(Suite.class)
@Suite.SuiteClasses({xx1.class, xx2.class})
public class RunAllUtilTestsSuite {
}
原理及框架說明
8、Runner 運行器
在運行測試代碼的時候是通過Runner來運行(也就是Runner的子類),比如,默認的JUnit4ClassRunner(不過這個已經廢棄了,看來有了新的)
它可以用@RunWith 注解來說明,需要注意的是它修飾的是類
里面包含兩個特殊的測試,參數化測試、套件打包測試
參數化測試:
@RunWith(Parameterized.class)
首先應該為這種測試專門生成一個新的類,因為他要用一個新的運行器。然后指定運行器為Parameterized。
然后在測試類中定義兩個變量,一個用於存放參數,另一個存放期待的結果。接下來定義測試數據的集合,用@Parameters標注進行修飾。
構造函數中對變量進行初始化,順序需要與集合中的順序一致,比如{參數,預期結果}。
打包測試:
通常在一個項目中,我們需要寫很多個測試類,打包測試就是一次執行多個或所有的測試類.
@RunWith(Suite.class) // 指定運行器
@Suite.SuiteClass({..,..,..}) // 指定需要同時測試的類
待測試的類:package com.test;
public class Calculator {
private static int result;// 靜態變量,用於存儲運行結果
public void add(int n) {
result = result + n;
}
public void substract(int n) {
result = result - 1;
// Bug: 正確的應該是 result = result - n;
}
public void multiply(int n) {
}
// 此方法尚未寫好
public void divide(int n) {
result = result / n;
}
public void square(int n) {
result = n * n;
}
public void squareRoot(int n) {
for (;;)
;
// Bug : 死循環
}
public void clear() {
// 將結果清零
result = 0;
}
public int getResult(){
return result;
}
}
// ------------- 基本測試
package com.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
public class CalculatorTest {
private static Calculator calculator = new Calculator();
@Before
public void setUp() throws Exception {
calculator.clear();
}
@After
public void tearDown() throws Exception {
}
@Test
public void testAdd() {
calculator.add(2);
calculator.add(3);
assertEquals(5, calculator.getResult());
}
@Test
public void testSubstract() {
calculator.add(2);
calculator.add(3);
assertEquals(5, calculator.getResult());
}
@Ignore("not implemented yet")
@Test
public void testMultiply() {
fail("Not yet implemented");
}
@Test
public void testDivide() {
calculator.add(8);
calculator.divide(2);
assertEquals(4, calculator.getResult());
}
@Test(expected = Exception.class)
public void DivideByZero(){
calculator.divide(0);
}
}
// ----------------- 多個參數測試
package com.test;
import static org.junit.Assert.*;
import java.util.Arrays;
import java.util.Collection;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
public class SquareTest {
Calculator calculator;
private int param;
private int result;
public SquareTest(int param,int result) {
this.param = param;
this.result = result;
}
@Before
public void setUp() throws Exception {
calculator = new Calculator();
}
@After
public void tearDown() throws Exception {
}
@Parameters
public static Collection data(){
return Arrays.asList( new Object[][]{{2,4},{0,0},{-2,4}});
}
@Test
public void testSquare() {
calculator.square(param);
assertEquals(calculator.getResult(),result );
}
}
// --------------- 打包測試
@RunWith(Suite.class)
@Suite.SuiteClasses({CalculatorTest.class, SquareTest.class })
public class AllCalculator {
}