单元测试应如何处理预期和意外的异常?

时间:2014-06-10 19:38:21

标签: java unit-testing junit

是否在预期的异常发生时通过了测试? 如果出现意外异常,它是否应该通过测试? 处理异常是多余的,因为它不能通过测试,因此可以作为测试吗?

4 个答案:

答案 0 :(得分:11)

测试预期的例外情况

您必须添加具有预期异常的expected属性,因此如果抛出指定的异常,测试将通过。否则,它将失败。

例如:

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

...或

@Test(expected = ArithmeticException.class)  
public void divisionWithException() {  
    int i = 1/0;
}

Documentation说:

  

Test annotation支持两个可选参数。首先,   预期,声明测试方法应抛出异常。如果它   不抛出异常或抛出不同的异常   宣布的那个,测试失败了。

测试时间

只是为了让您知道,您还可以测试超时。

  

第二个可选参数timeout会导致测试失败   花费的时间超过指定的时钟时间(以   毫秒)。以下测试失败:

@Test(timeout=100) 
public void infinity() {
   while(true);
}

希望能提供帮助

答案 1 :(得分:2)

对于预期的异常,使用JUnit有很好的方法:

@Test(expected=NullPointerException.class)
public void testNullPointerExceptionIsThrown() {
    ArrayList emptyList;
    emptyList.size(); //or add, remove etc. 
}

JUnit中的上述测试将传递,因为它是使用@Test注释声明的,测试方法应该期望抛出空指针异常。

答案 2 :(得分:1)

如果测试期望某些数据会出现特定异常,那么,如果抛出该特定异常,则传递

如果测试期望某些数据出现特定异常,没有异常预期,那么,它应该失败如果抛出任何超出预期的异常。

不要自己处理抛出的异常,除非你必须(如果必须,那是一种测试气味 - 重新审视你处理异常的原因)。向JUnit指出您期望异常的最佳方法是使用expected注释上的@Test字段。

例如,假设您正在测试一个罗马数字转换器,并说任何不在正常罗马数字中的东西都是非法参数(即P)。

@Test(expected = IllegalArgumentException.class)
public void method_takesIllegalArgument_throwsIllegalArgumentException() {
    convertRomanNumeralToNumber("PXL");
}

答案 3 :(得分:0)

例外是API的一部分,有时也是明确的。因此,您应该记录代码可能抛出的异常,并编写测试以确保它们得到维护。

@Test(expected = ThisException.class)是一个很好的起点,如果你有JUnit4并且正在编写一个throw new ThisException(...)的方法。请注意选择最合适的例外的值:如果您变得懒惰并使用expected = Exception.class,那么如果您更改为throw new ThatException(...),您的代码会接受它。当且仅当没有抛出异常(JUnit将为您强制执行)时,您的非异常代码才会通过,并且您的测试应该仔细指定预期的异常,以便当且仅当抛出该特定异常时它们才会失败。 / p>

作为评论中提到的dhillerExpectedException rule也是JUnit4的一个非常好的选择,并允许进一步检查抛出的异常:

@Rule ExpectedException expectedException = ExpectedException.none();

@Test public void yourTest() {
  // This is for demonstration. Don't actually verify the exact exception message
  // unless you want to have to update your test if the text ever changes.
  expectedException.expectMessage("Error 743: Toilet paper missing.");
  systemUnderTest.doStuff();
}

但是如果你真的想在捕获异常后检查状态,最好的方法是JUnit3风格:

@Test public void yourTest() {
  try {
    systemUnderTest.doStuff();
    fail("ThisException expected.");
  } catch (ThisException expected) {
    assertEquals(743, expected.getErrorNumber());
  }

  // In both @Test(expected=...) and ExpectedException code, the
  // exception-throwing line will be the last executed line, because Java will
  // still traverse the call stack until it reaches a try block--which will be
  // inside the JUnit framework in those cases. The only way to prevent this
  // behavior is to use your own try block.

  // This is especially useful to test the state of the system after the
  // exception is caught.

  assertFalse(systemUnderTest.hasToiletPaper());
}

另一个声称在此帮助的图书馆是catch-exception;但是,截至2014年5月,该项目似乎处于维护模式(由Java 8淘汰),而且很像Mockito catch-exception只能操纵非final方法。