四、執行個體總結
1. 參數化測試
有時一個測試方法,不同的參數值會產生不同的結果,那麼我們為了測試全面,會把多個參數值都寫出來並一一斷言測試,這樣有時難免費時費力,這是我們便可以採用參數化測試來解決這個問題。參數化測試就好比把一個“輸入值,期望值”的集合傳入給測試方法,達到一次性測試的目的。
package test;import static org.junit.Assert.*;import java.util.Arrays;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 FibonacciTest { @Parameters(name = "{index}: fib({0})={1}") public static Iterable<Object[]> data() { return Arrays.asList(new Object[][] { { 0, 0 }, { 1, 1 }, { 2, 1 }, { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 } }); } private int input; private int expected; public FibonacciTest(int input, int expected) { this.input = input; this.expected = expected; } @Test public void test() { assertEquals(expected, Fibonacci.compute(input)); }}class Fibonacci {public static int compute(int input) {int result;switch (input) {case 0:result = 0;break;case 1:case 2:result = 1;break;case 3:result = 2;break;case 4:result = 3;break;case 5:result = 5;break;case 6:result = 8;break;default:result = 0;}return result;}}
@Parameters註解參數name,實際是測試方法名稱。由於一個test()方法就完成了所有測試,那假如某一組測試資料有問題,那在Junit的結果頁面裡該如何呈現?因此採用name實際上就是區分每個測試資料的測試方法名。如:
2. 打包測試
同樣,如果一個項目中有很多個測試案例,如果一個個測試也很麻煩,因此打包測試就是一次性測試完成包中含有的所有測試案例。
package test;import org.junit.runner.RunWith;import org.junit.runners.Suite;@RunWith(Suite.class)@Suite.SuiteClasses({ AssertTests.class, FibonacciTest.class, JDemoTest.class })public class AllCaseTest {}
這個功能也需要使用一個特殊的Runner ,需要向@RunWith註解傳遞一個參數Suite.class 。同時,我們還需要另外一個註解@Suite.SuiteClasses,來表明這個類是一個打包測試類別。並將需要打包的類作為參數傳遞給該註解就可以了。至於AllCaseTest隨便起一個類名,內容為空白既可。運行AllCaseTest類即可完成打包測試
3. 異常測試
異常測試與普通斷言測試不同,共有三種方法,其中最為靈活的是第三種,可以與斷言結合使用
第一種:
@Test(expected= IndexOutOfBoundsException.class) public void empty() { new ArrayList<Object>().get(0); }
第二種:
@Test public void testExceptionMessage() { try { new ArrayList<Object>().get(0); fail("Expected an IndexOutOfBoundsException to be thrown"); } catch (IndexOutOfBoundsException anIndexOutOfBoundsException) { assertThat(anIndexOutOfBoundsException.getMessage(), is("Index: 0, Size: 0")); } }
第三種:
@Rule public ExpectedException thrown = ExpectedException.none(); @Test public void shouldTestExceptionMessage() throws IndexOutOfBoundsException { List<Object> list = new ArrayList<Object>(); thrown.expect(IndexOutOfBoundsException.class); thrown.expectMessage("Index: 0, Size: 0"); list.get(0); Assert.assertEquals(1, list.get(0)); }
在上述幾種方法中,無論是expected還是expect都表示期望拋出的異常,假如某一方法,當參數為某一值時會拋出異常,那麼使用第一種方法就必須為該參數單獨寫一個測試方法來測試異常,而無法與其他參數值一同寫在一個測試方法裡,所以顯得累贅。第二種方法雖然解決這個問題,但是寫法不僅繁瑣也不利於理解。而第三種犯法,不僅能動態更改期望拋出的異常,與Assert 陳述式結合的也非常好,因此推薦使用該方法來測試異常。
4. 限時測試
有時為了防止出現死迴圈或者方法執行過長(或檢查方法效率),而需要使用到限時測試。顧名思義,就是超出設定時間即視為測試失敗。共有兩種寫法。
第一種:
@Test(timeout=1000)public void testWithTimeout() { ...}
第二種:
public class HasGlobalTimeout { public static String log; @Rule public Timeout globalTimeout = new Timeout(10000); // 10 seconds max per method tested @Test public void testInfiniteLoop1() { log += "ran1"; for (;;) { } } @Test public void testInfiniteLoop2() { log += "ran2"; for (;;) { } }}
其中,第二種方法與異常測試的第三種方法的寫法類似。也是推薦的寫法。
至此,Junit的教程總結性文章已介紹完了。通過系統總結也進一步加深了對Junit的認識,希望也能同樣協助到對Junit還不太理解的朋友。如果大家還有什麼好的建議和用法,很歡迎能提出來一起交流。