2013-05-16 63 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