單元測試是編寫測試代碼,應(yīng)該準確、快速地保證程序基本模塊的正確性。
好的單元測試的標準
JUnit是Java單元測試框架,已經(jīng)在Eclipse中默認安裝。
JUnit4通過注解的方式來識別測試方法。目前支持的主要注解有:
基本測試
public class Calculator { private static int result; // 靜態(tài)變量,用于存儲運行結(jié)果 public void add(int n) { result = result + n; } public void substract(int n) { result = result - 1; //Bug: 正確的應(yīng)該是 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 : 死循環(huán) } public void clear() { // 將結(jié)果清零 result = 0; } public int getResult(){ return result; }}
public class CalculatorTest { private static Calculator calculator = new Calculator(); @Before public void setUp() throws Exception { calculator.clear(); } @Test public void testAdd() { calculator.add(3); calculator.add(4); assertEquals(7, calculator.getResult()); } @Test public void testSubstract() { calculator.add(8); calculator.substract(3); assertEquals(5, calculator.getResult()); } @Ignore("Multiply() Not yet implemented") @Test public void testMultiply() { fail("Not yet implemented"); } @Test public void testDivide() { calculator.add(8); calculator.divide(2); assertEquals(4, calculator.getResult()); }}
@Test(timeout = 1000) public void squareRoot() { calculator.squareRoot(4); assertEquals(2, calculator.getResult()); }
Timeout參數(shù)表明了你要設(shè)定的時間,單位為毫秒,因此1000就代表1秒。
JAVA中的異常處理也是一個重點,因此你經(jīng)常會編寫一些需要拋出異常的函數(shù)。那么,如果你覺得一個函數(shù)應(yīng)該拋出異常,但是它沒拋出,這算不算Bug呢?這當然是Bug,并JUnit也考慮到了這一點,來幫助我們找到這種Bug。例如,我們寫的計算器類有除法功能,如果除數(shù)是一個0,那么必然要拋出“除0異?!?。因此,我們很有必要對這些進行測試。代碼如下:
@Test(expected = ArithmeticException.class) public void divideByZero(){ calculator.divide(0); }
如上述代碼所示,我們需要使用@Test標注的expected屬性,將我們要檢驗的異常傳遞給他,這樣JUnit框架就能自動幫我們檢測是否拋出了我們指定的異常。
參數(shù)化測試
我們可能遇到過這樣的函數(shù),它的參數(shù)有許多特殊值,或者說他的參數(shù)分為很多個區(qū)域。
例如,測試一下“計算一個數(shù)的平方”這個函數(shù),暫且分三類:正數(shù)、0、負數(shù)。在編寫測試的時候,至少要寫3個測試,把這3種情況都包含了,這確實是一件很麻煩的事情。測試代碼如下:
public class AdvancedTest { private static Calculator calculator = new Calculator(); @Before public void clearCalculator(){ calculator.clear(); } @Test public void square1() { calculator.square(2); assertEquals(4, calculator.getResult()); } @Test public void square2(){ calculator.square(0); assertEquals(0, calculator.getResult()); } @Test public void square3(){ calculator.square(-3); assertEquals(9, calculator.getResult()); } }
為了簡化類似的測試,JUnit4提出了“參數(shù)化測試”的概念,只寫一個測試函數(shù),把這若干種情況作為參數(shù)傳遞進去,一次性的完成測試。代碼如下:
@RunWith(Parameterized.class) public class SquareTest{ private static Calculator calculator = new Calculator(); private int param; private int result; @Parameters public static Collection data() { return Arrays.asList(new Object[][]{ {2, 4}, {0, 0}, {-3, 9}, }); } //構(gòu)造函數(shù),對變量進行初始化 public SquareTest(int param, int result){ this.param = param; this.result = result; } @Test public void square(){ calculator.square(param); assertEquals(result, calculator.getResult()); } }
執(zhí)行了3次該測試類,依次采用了數(shù)據(jù)集合中的數(shù)據(jù){處理值,預(yù)期處理結(jié)果},結(jié)果如下: