Junit使用教程(三)

四、實例總結

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都表示期望拋出的異常,假如某一方法,當參數爲某一值時會拋出異常,那麼使用第一種方法就必須爲該參數單獨寫一個測試方法來測試異常,而無法與其他參數值一同寫在一個測試方法裏,所以顯得累贅。第二種方法雖然解決這個問題,但是寫法不僅繁瑣也不利於理解。而第三種犯法,不僅能動態更改期望拋出的異常,與斷言語句結合的也非常好,因此推薦使用該方法來測試異常。

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還不太理解的朋友。如果大家還有什麼好的建議和用法,很歡迎能提出來一起交流。

發佈了110 篇原創文章 · 獲贊 197 · 訪問量 320萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章