如何使用JUnit来测试某些代码是否抛出异常?
我当然可以这样做:
@Test
public void testFooThrowsIndexOutOfBoundsException() {
boolean thrown = false;
try {
foo.doStuff();
} catch (IndexOutOfBoundsException e) {
thrown = true;
}
assertTrue(thrown);
}
我记得,对于这类情况,有一个注释或Assert.xyz之类的东西远没有JUnit那么笨拙,更符合JUnit的精神。
我在这里尝试了许多方法,但它们要么很复杂,要么不太符合我的要求。事实上,可以非常简单地编写一个助手方法:
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代码。
我使用assertTrue(布尔值)和try/catch组合来查找要抛出的预期异常。下面是一个示例:
public void testConstructor() {
boolean expectedExceptionThrown;
try {
// Call constructor with bad arguments
double a = 1;
double b = 2;
double c = a + b; // In my example, this is an invalid option for c
new Triangle(a, b, c);
expectedExceptionThrown = false; // because it successfully constructed the object
}
catch(IllegalArgumentException e) {
expectedExceptionThrown = true; // because I'm in this catch block
}
catch(Exception e) {
expectedExceptionThrown = false; // because it threw an exception but not the one expected
}
assertTrue(expectedExceptionThrown);
}
现在JUnit 5和JUnit 4.13已经发布,最好的选择是使用Assertions.assertThrows()(针对JUnit 5)和Assertions.AssertThrow()(对于JUnit 4.13)JUnit 5用户指南。
下面是一个验证抛出异常的示例,并使用Truth对异常消息进行断言:
public class FooTest {
@Test
public void doStuffThrowsIndexOutOfBoundsException() {
Foo foo = new Foo();
IndexOutOfBoundsException e = assertThrows(
IndexOutOfBoundsException.class, foo::doStuff);
assertThat(e).hasMessageThat().contains("woops!");
}
}
与其他答案中的方法相比,优势在于:
内置于JUnit如果lambda中的代码没有引发异常,则会得到一个有用的异常消息;如果它引发了不同的异常,则将得到一个堆栈跟踪简明的允许您的测试遵循排列动作断言您可以精确地指示希望抛出异常的代码您不需要在throws子句中列出预期的异常您可以使用自己选择的断言框架对捕获的异常进行断言
只需制作一个可以关闭和打开的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();