我们如何断言在JUnit 4测试中引发了某种异常?

时间:2020-03-06 14:57:50  来源:igfitidea点击:

如何惯用JUnit4来测试某些代码引发异常?

虽然我当然可以做这样的事情:

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

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

  assertTrue(thrown);
}

我记得在这种情况下,有一个批注或者一个Assert.xyz或者一些不那么杂乱无章的东西,更像是JUnit的精髓。

解决方案

怎么做:捕获一个非常通用的异常,确保它使它脱离catch块,然后断言该异常的类就是我们期望的异常。如果a)异常的类型错误(例如,如果我们改为使用Null指针),并且b)从未引发异常,则该断言将失败。

public void testFooThrowsIndexOutOfBoundsException() {
  Throwable e = null;

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

  assertTrue(e instanceof IndexOutOfBoundsException);
}

JUnit对此具有内置支持,并带有" expected"属性

JUnit 4为此提供支持:

@Test(expected = IndexOutOfBoundsException.class)
public void testIndexOutOfBoundsException() {
    ArrayList emptyList = new ArrayList();
    Object o = emptyList.get(0);
}

参考:https://junit.org/junit4/faq.html#atests_7

使用预期的异常时要小心,因为它仅断言该方法引发了该异常,而不是测试中的特定代码行。

我倾向于将其用于测试参数验证,因为此类方法通常非常简单,但最好将更复杂的测试用于:

try {
    methodThatShouldThrow();
    fail( "My method didn't throw when I expected it to" );
} catch (MyException expectedException) {
}

运用判断。

编辑现在,JUnit5已发布,最好的选择是使用Assertions.assertThrows()(请参阅我的其他答案)。

如果尚未迁移到JUnit 5,但可以使用JUnit 4.7,则可以使用ExpectedException规则:

public class FooTest {
  @Rule
  public final ExpectedException exception = ExpectedException.none();

  @Test
  public void doStuffThrowsIndexOutOfBoundsException() {
    Foo foo = new Foo();

    exception.expect(IndexOutOfBoundsException.class);
    foo.doStuff();
  }
}

这比@Test(expected = IndexOutOfBoundsException.class)好得多,因为如果在foo.doStuff()之前抛出IndexOutOfBoundsException,则测试将失败。

详情请参阅这篇文章