2013-05-16 64 views
21

我寫了一些測試用例來測試一些方法。但有些方法會拋出異常。我做得對嗎?如何在junit中處理異常

private void testNumber(String word, int number) { 
    try { 
     assertEquals(word, service.convert(number)); 
    } catch (OutOfRangeNumberException e) { 
     Assert.fail("Test failed : " + e.getMessage()); 
    } 
} 

@Test 
public final void testZero() { 
    testNumber("zero", 0); 
} 

如果我通過-45,它將失敗,OutOfRangeException,但我沒能測試特定的異常像@Test(Expected...)

回答

6

你不需要捕獲該異常失敗的考驗。放手吧(通過聲明throws),它無論如何都會失敗。

另一種情況是,當您真正期望出現異常時,則在try塊結束時放置失敗。

例如:

@Test 
public void testInvalidNumber() { 
    try { 
     String dummy = service.convert(-1)); 
     Assert.fail("Fail! Method was expected to throw an exception because negative numbers are not supported.") 
    } catch (OutOfRangeException e) { 
     // expected 
    } 
} 

您可以使用這種測試來驗證,如果你的代碼是正確的驗證輸入和處理無效的輸入與適當的異常。

+1

的ExpectedException是測試預期的例外的首選方式。 –

+0

我同意並且已經提出了Eric的回答。 – javadeveloper

+0

如果您需要檢查異常的結構,則只需要ExpectedException。例如,CmisExceptions應該在它們內部設置一個特定的故障原因。我不得不編寫測試來檢查,並且爲此使用了Hamcrest匹配器。如果您只是期望出現異常,請將參數用於@Test。 –

15

刪除try-catch塊,並添加throws Exception到您的測試方法,如:

@Test 
public final void testZero() throws Exception { 
    assertEquals("zero", service.convert(0)); 
} 

Junit認爲失敗的測試會拋出異常,你抓住他們只是從能夠正確地報告他們停止JUnit的。這樣,@Test註釋的預期屬性也可以工作。

45

意外的異常是測試失敗,所以您既不需要也不想捕獲一個異常。

@Test 
public void canConvertStringsToDecimals() { 
    String str = "1.234"; 
    Assert.assertEquals(1.234, service.convert(str), 1.0e-4); 
} 

直到service不會引發IllegalArgumentException因爲str中有一個小數點,這將是一個簡單的測試失敗。

預期的異常應該由@Test的可選參數expected參數處理。

@Test(expected=NullPointerException.class) 
public void cannotConvertNulls() { 
    service.convert(null); 
} 

如果程序員又懶惰又扔Exception,或者如果他有service回報0.0,會導致測試失敗。只有NPE會成功。請注意,預期的異常的子類也適用。對於NPE s這很少見,但與IOException s和SQLException s很相似。

在極少數情況下,您想要測試特定的異常消息,請使用新版ExpectedException JUnit @Rule。現在

@Rule 
public ExpectedException thrown= ExpectedException.none(); 
@Test 
public void messageIncludesErrantTemperature() { 
    thrown.expect(IllegalArgumentException.class); 
    thrown.expectMessage("-400"); // Tests that the message contains -400. 
    temperatureGauge.setTemperature(-400); 
} 

,除非setTemperature拋出IAE和消息包含用戶試圖設定的溫度,則測試失敗。該規則可以以更復雜的方式使用。


你舉的例子可以最好地處理:

private void testNumber(String word, int number) 
     throws OutOfRangeNumberException { 
    assertEquals(word, service.convert(number)); 
} 

@Test 
public final void testZero() 
     throws OutOfRangeNumberException { 
    testNumber("zero", 0); 
} 

可以內嵌testNumber;現在,它沒有多大幫助。你可以把它變成一個參數化的測試類。

2

有幾種策略可供您在測試中處理預期的異常。我認爲上面已經提到了JUnit註釋和try/catch成語。我想提請注意Lambda表達式的Java 8選項。

例如給出:

class DummyService { 
public void someMethod() { 
    throw new RuntimeException("Runtime exception occurred"); 
} 

public void someOtherMethod(boolean b) { 
    throw new RuntimeException("Runtime exception occurred", 
      new IllegalStateException("Illegal state")); 
} 

}

你可以這樣做:

@Test 
public void verifiesCauseType() { 
    // lambda expression 
    assertThrown(() -> new DummyService().someOtherMethod(true)) 
      // assertions 
      .isInstanceOf(RuntimeException.class) 
      .hasMessage("Runtime exception occurred") 
      .hasCauseInstanceOf(IllegalStateException.class); 
} 

看看這個博客裏面涵蓋了大部分的結合實例的選項。

http://blog.codeleak.pl/2013/07/3-ways-of-handling-exceptions-in-junit.html

而這一次更充分地解釋了Java 8 LAMBDA選項:

http://blog.codeleak.pl/2014/07/junit-testing-exception-with-java-8-and-lambda-expressions.html