JUnit中測試異常拋出的方法

最近在作TWU關於TDD的做業,對JUnit中測試異常拋出的方法進行了一些學習和思考。框架

在進行單元測試的時候有的時候須要測試某一方法是否拋出了正確的異常。例如,我有一個方法,裏面對一個List進行讀取操做,可能會拋出IndexOutOfBoundsException,我但願在單元測試中經過測試保證該方法會正確的拋出正確類型的異常。總結起來這樣的測試異常是否被正確拋出的方法有三種:單元測試

1. try…fail...catch…學習

@Test
public voidtestExceptionMessage() {
      try {
          new ArrayList<Object>().get(0);
          fail("Expected an IndexOutOfBoundsException to be thrown");
      } catch (IndexOutOfBoundsException anIndexOutOfBoundsException) {
          assertThat(anIndexOutOfBoundsException.getMessage(), is("Index: 0, Size: 0"));
      }  
}

這種寫法看上去和實現類的寫法很類似,當沒有異常被拋出的時候fail方法會被調用,輸出測試失敗的信息。 測試

2.@Test(expected=xxx) this

@Test(expected= IndexOutOfBoundsException.class) 
  public void empty() { 
       new ArrayList<Object>().get(0);  
}

這種寫法看上去簡單了一些,可是它有一個潛在的問題:當被標記的這個測試方法中的任何一個操做拋出了相應的異常時,這個測試就會經過。這就意味着有可能拋出異常的地方並非咱們指望的那個操做。雖然這種狀況能夠在寫test case的時候人爲的避免,可是仍是有更好的方法來測試異常拋出。spa

3.ExpectedException Rulecode

@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); // execution will never get past this line  
}

這種方法除了能夠指按期望拋出的異常類型以外還能夠指定在拋出異常時但願同時給出的異常信息。它須要在測試以前使用Rule標記來指定一個ExpectedException,並在測試相應操做以前指按期望的Exception類型(如IndexOutOfBoundException.class)blog

這三種方法均可以作到測試相應的操做是否拋出了指望的異常,可是哪一種方法更好更適合使用呢?個人總結是:get

@Test(expected=xxx)  >  根本不測異常是否正確拋出
ExpectedException  >  @Test(expected=xxx)
try…fail…catch  >  ExpectedExceptionit

我之因此認爲try…fail…catch方法比ExpectedException好是由於:

1. try…fail…catch更符合通常的test function的風格,先進行某項操做,在對結果進行assert。而ExpectedException的順序確實先指明期待的結果再進行相應的操做。

2. 雖然TDD的最佳實踐是每一個test function只有一個assert,可是仍是在有些狀況下會在同一個test function裏使用多個assert來對不一樣的方面進行測試。可是使用ExpectedException進行異常測試後,當前的test function就結束了,若是在expect的相應操做以後還有assert的話會被自動跳過,而try…fail…catch則不會跳出當前test function, 其後面的assert依然會被順序執行。

3. ExpectedException是JUnit提供的,所以在使用別的測試框架時這樣的測試方法無效。而try/catch有更多的測試框架支持(fail也是JUnit提供的。使用別的測試框架的時候不能使用fail來給出測試失敗的信息)

相關文章
相關標籤/搜索