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

我当然可以这样做:

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

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

  assertTrue(thrown);
}

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


当前回答

只需制作一个可以关闭和打开的Matcher,如下所示:

public class ExceptionMatcher extends BaseMatcher<Throwable> {
    private boolean active = true;
    private Class<? extends Throwable> throwable;

    public ExceptionMatcher(Class<? extends Throwable> throwable) {
        this.throwable = throwable;
    }

    public void on() {
        this.active = true;
    }

    public void off() {
        this.active = false;
    }

    @Override
    public boolean matches(Object object) {
        return active && throwable.isAssignableFrom(object.getClass());
    }

    @Override
    public void describeTo(Description description) {
        description.appendText("not the covered exception type");
    }
}

要使用它:

add public ExpectedException exception=ExpectedException.none();,那么:

ExceptionMatcher exMatch = new ExceptionMatcher(MyException.class);
exception.expect(exMatch);
someObject.somethingThatThrowsMyException();
exMatch.off();

其他回答

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

public void testFooThrowsIndexOutOfBoundsException() {
  Throwable e = null;

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

  assertTrue(e instanceof IndexOutOfBoundsException);
}

BDD风格解决方案:JUnit 4+Catch异常+AssertJ

import static com.googlecode.catchexception.apis.BDDCatchException.*;

@Test
public void testFooThrowsIndexOutOfBoundsException() {

    when(() -> foo.doStuff());

    then(caughtException()).isInstanceOf(IndexOutOfBoundsException.class);

}

依赖关系

eu.codearte.catch-exception:catch-exception:2.0

只需制作一个可以关闭和打开的Matcher,如下所示:

public class ExceptionMatcher extends BaseMatcher<Throwable> {
    private boolean active = true;
    private Class<? extends Throwable> throwable;

    public ExceptionMatcher(Class<? extends Throwable> throwable) {
        this.throwable = throwable;
    }

    public void on() {
        this.active = true;
    }

    public void off() {
        this.active = false;
    }

    @Override
    public boolean matches(Object object) {
        return active && throwable.isAssignableFrom(object.getClass());
    }

    @Override
    public void describeTo(Description description) {
        description.appendText("not the covered exception type");
    }
}

要使用它:

add public ExpectedException exception=ExpectedException.none();,那么:

ExceptionMatcher exMatch = new ExceptionMatcher(MyException.class);
exception.expect(exMatch);
someObject.somethingThatThrowsMyException();
exMatch.off();

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

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

不要这样做:

@Rule    
public ExpectedException expectedException;

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

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

为了解决同样的问题,我设立了一个小项目:http://code.google.com/p/catch-exception/

使用这个小助手,您可以编写

verifyException(foo, IndexOutOfBoundsException.class).doStuff();

这比JUnit 4.7的ExpectedException规则更详细。与skaffman提供的解决方案相比,您可以指定期望在哪行代码中出现异常。我希望这有帮助。