如何使用JUnit来测试某些代码是否抛出异常?
我当然可以这样做:
@Test
public void testFooThrowsIndexOutOfBoundsException() {
boolean thrown = false;
try {
foo.doStuff();
} catch (IndexOutOfBoundsException e) {
thrown = true;
}
assertTrue(thrown);
}
我记得,对于这类情况,有一个注释或Assert.xyz之类的东西远没有JUnit那么笨拙,更符合JUnit的精神。
使用Java 8,您可以创建一个方法,将要检查的代码和预期异常作为参数:
private void expectException(Runnable r, Class<?> clazz) {
try {
r.run();
fail("Expected: " + clazz.getSimpleName() + " but not thrown");
} catch (Exception e) {
if (!clazz.isInstance(e)) fail("Expected: " + clazz.getSimpleName() + " but " + e.getClass().getSimpleName() + " found", e);
}
}
然后在测试中:
expectException(() -> list.sublist(0, 2).get(2), IndexOutOfBoundsException.class);
优点:
不依赖任何库本地化检查-更精确,如果需要,允许在一个测试中有多个这样的断言易于使用
Junit4与Java8的解决方案是使用此功能:
public Throwable assertThrows(Class<? extends Throwable> expectedException, java.util.concurrent.Callable<?> funky) {
try {
funky.call();
} catch (Throwable e) {
if (expectedException.isInstance(e)) {
return e;
}
throw new AssertionError(
String.format("Expected [%s] to be thrown, but was [%s]", expectedException, e));
}
throw new AssertionError(
String.format("Expected [%s] to be thrown, but nothing was thrown.", expectedException));
}
用法如下:
assertThrows(ValidationException.class,
() -> finalObject.checkSomething(null));
注意,唯一的限制是在lambda表达式中使用最终对象引用。此解决方案允许使用@test(expected=IndexOutOfBoundsException.class)解决方案继续测试断言,而不是期望在方法级别可以执行。