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

我当然可以这样做:

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

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

  assertTrue(thrown);
}

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


当前回答

除了NamShubWriter所说的,还要确保:

ExpectedException实例是公共的(相关问题)ExpectedException未在@Before方法中实例化。这篇文章清楚地解释了JUnit执行顺序的所有复杂性。

不要这样做:

@Rule    
public ExpectedException expectedException;

@Before
public void setup()
{
    expectedException = ExpectedException.none();
}

最后,这篇博客文章清楚地说明了如何断言抛出了某个异常。

其他回答

在我的例子中,我总是从数据库中得到RuntimeException,但消息不同。需要分别处理异常。以下是我测试它的方法:

@Test
public void testThrowsExceptionWhenWrongSku() {

    // Given
    String articleSimpleSku = "999-999";
    int amountOfTransactions = 1;
    Exception exception = null;

    // When
    try {
        createNInboundTransactionsForSku(amountOfTransactions, articleSimpleSku);
    } catch (RuntimeException e) {
        exception = e;
    }

    // Then
    shouldValidateThrowsExceptionWithMessage(exception, MESSAGE_NON_EXISTENT_SKU);
}

private void shouldValidateThrowsExceptionWithMessage(final Exception e, final String message) {
    assertNotNull(e);
    assertTrue(e.getMessage().contains(message));
}

编辑:现在JUnit 5和JUnit 4.13已经发布,最好的选择是使用Assertions.assertThrows()(针对JUnit 5)和Assertions.AssertThrow()(对于JUnit 4.13+)。有关详细信息,请参阅我的其他答案。

如果您尚未迁移到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(预期=IndexOutOfBoundsException.class)好得多,因为如果在foo.doStuff()之前抛出IndexOutofBoundsExcept,测试将失败

有关详细信息,请参阅本文。

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

public void testFooThrowsIndexOutOfBoundsException() {
  Throwable e = null;

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

  assertTrue(e instanceof IndexOutOfBoundsException);
}

我在这里尝试了许多方法,但它们要么很复杂,要么不太符合我的要求。事实上,可以非常简单地编写一个助手方法:

public class ExceptionAssertions {
    public static void assertException(BlastContainer blastContainer ) {
        boolean caughtException = false;
        try {
            blastContainer.test();
        } catch( Exception e ) {
            caughtException = true;
        }
        if( !caughtException ) {
            throw new AssertionFailedError("exception expected to be thrown, but was not");
        }
    }
    public static interface BlastContainer {
        public void test() throws Exception;
    }
}

这样使用:

assertException(new BlastContainer() {
    @Override
    public void test() throws Exception {
        doSomethingThatShouldExceptHere();
    }
});

零依赖:无需mockito,无需powermock;在期末考试中表现很好。

在junit中,有四种方法可以测试异常。

六月5.x

对于junit5.x,可以使用assertThrows,如下所示@测试public void testFooThrowsIndexOutOfBoundsException(){抛出异常=assertThrows(IndexOutOfBoundsException.class,()->foo.doStuff());assertEquals(“预期消息”,exception.getMessage());}

六月4.x

对于junit4.x,使用测试注释的可选“expected”属性@测试(应为IndexOutOfBoundsException.class)public void testFooThrowsIndexOutOfBoundsException(){foo.doStuff();}对于junit4.x,请使用ExpectedException规则公共类XxxTest{@规则引发了public ExpectedException=ExpectedException.none();@测试public void testFooThrowsIndexOutOfBoundsException(){引发.预期(IndexOutOfBoundsException.class)//您可以像这样测试异常消息抛出.expectMessage(“预期消息”);foo.doStuff();}}您还可以使用junit3框架下广泛使用的经典try/catch方法@测试public void testFooThrowsIndexOutOfBoundsException(){尝试{foo.doStuff();fail(“未发生预期的异常。”);}catch(IndexOutOfBoundsException e){//如果执行到达这里,//它表示发生了此异常。//所以我们不需要处理它。}}所以如果你喜欢junit 5,那么你应该喜欢第一个当您只想测试异常类型时,使用第二种方法当需要进一步测试异常消息时,使用前两个和后两个如果您使用junit 3,则首选第四个有关详细信息,您可以阅读本文档和junit5用户指南。