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

我当然可以这样做:

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

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

  assertTrue(thrown);
}

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


当前回答

在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用户指南。

其他回答

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

优点:

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

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

public void testFooThrowsIndexOutOfBoundsException() {
  Throwable e = null;

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

  assertTrue(e instanceof IndexOutOfBoundsException);
}

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获得非常好的工作版本。

    @Test(expectedException=IndexOutOfBoundsException.class) 
    public void  testFooThrowsIndexOutOfBoundsException() throws Exception {
         doThrow(IndexOutOfBoundsException.class).when(foo).doStuff();  
         try {
             foo.doStuff(); 
            } catch (IndexOutOfBoundsException e) {
                       assertEquals(IndexOutOfBoundsException .class, ex.getCause().getClass());
                      throw e;

               }

    }

下面是检查方法是否抛出了正确异常的另一种方法。

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

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;在期末考试中表现很好。