如何使用JUnit来测试某些代码是否抛出异常?
我当然可以这样做:
@Test
public void testFooThrowsIndexOutOfBoundsException() {
boolean thrown = false;
try {
foo.doStuff();
} catch (IndexOutOfBoundsException e) {
thrown = true;
}
assertTrue(thrown);
}
我记得,对于这类情况,有一个注释或Assert.xyz之类的东西远没有JUnit那么笨拙,更符合JUnit的精神。
使用可以与JUnit一起使用的AssertJ断言:
import static org.assertj.core.api.Assertions.*;
@Test
public void testFooThrowsIndexOutOfBoundsException() {
Foo foo = new Foo();
assertThatThrownBy(() -> foo.doStuff())
.isInstanceOf(IndexOutOfBoundsException.class);
}
它比@Test(expected=IndexOutOfBoundsException.class)更好,因为它保证了测试中的预期行抛出了异常,并允许您更容易地检查有关异常的详细信息,例如消息:
assertThatThrownBy(() ->
{
throw new Exception("boom!");
})
.isInstanceOf(Exception.class)
.hasMessageContaining("boom");
Maven/Gradle说明。
编辑:现在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,测试将失败
有关详细信息,请参阅本文。
我想评论一下这个问题的解决方案,它避免了任何与异常相关的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);
}
IMHO,在JUnit中检查异常的最佳方法是try/catch/fail/assert模式:
// this try block should be as small as possible,
// as you want to make sure you only catch exceptions from your code
try {
sut.doThing();
fail(); // fail if this does not throw any exception
} catch(MyException e) { // only catch the exception you expect,
// otherwise you may catch an exception for a dependency unexpectedly
// a strong assertion on the message,
// in case the exception comes from anywhere an unexpected line of code,
// especially important if your checking IllegalArgumentExceptions
assertEquals("the message I get", e.getMessage());
}
assertTrue对某些人来说可能有点强,所以assertThat(例如getMessage(),containsString(“消息”);可能更可取。