如何使用JUnit来测试某些代码是否抛出异常?

我当然可以这样做:

@Test
public void testFooThrowsIndexOutOfBoundsException() {
  boolean thrown = false;

  try {
    foo.doStuff();
  } catch (IndexOutOfBoundsException e) {
    thrown = true;
  }

  assertTrue(thrown);
}

我记得,对于这类情况,有一个注释或Assert.xyz之类的东西远没有JUnit那么笨拙,更符合JUnit的精神。


当前回答

您也可以这样做:

@Test
public void testFooThrowsIndexOutOfBoundsException() {
    try {
        foo.doStuff();
        assert false;
    } catch (IndexOutOfBoundsException e) {
        assert true;
    }
}

其他回答

JUnit内置了对此的支持,并带有“expected”属性。

这样如何:捕获一个非常普通的异常,确保它从catch块中取出,然后断言该异常的类是您期望的。如果a)异常类型错误(例如,如果您使用了空指针),并且b)该异常从未被抛出,则该断言将失败。

public void testFooThrowsIndexOutOfBoundsException() {
  Throwable e = null;

  try {
    foo.doStuff();
  } catch (Throwable ex) {
    e = ex;
  }

  assertTrue(e instanceof IndexOutOfBoundsException);
}

我建议库assertj核心处理junit测试中的异常

在java 8中,如下所示:

//given

//when
Throwable throwable = catchThrowable(() -> anyService.anyMethod(object));

//then
AnyException anyException = (AnyException) throwable;
assertThat(anyException.getMessage()).isEqualTo("........");
assertThat(exception.getCode()).isEqualTo(".......);

使用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);

优点:

不依赖任何库本地化检查-更精确,如果需要,允许在一个测试中有多个这样的断言易于使用

JUnit框架具有assertThrows()方法:

ArithmeticException exception = assertThrows(ArithmeticException.class, () ->
    calculator.divide(1, 0));
assertEquals("/ by zero", exception.getMessage());

对于JUnit 5,它位于org.unit.jupiter.api.Assertions类中;对于JUnit 4.13,它位于org.JUnit.Assert类中;对于JUnit4的早期版本:只需将org.JUnit.jupiter:junitjupiterapi上的引用添加到项目中,就可以从JUnit5获得非常好的工作版本。