Historically, assertions against an exception thrown by a JUnit test case involved one of the following:
try/fail/catch idiomexpected element of the @Test annotationExpectedException ruleIn JUnit5:
The wrap-and-assert approach now has some lambda sugar, for example:
RuntimeException actual = assertThrows(RuntimeException.class, () -> {
// code-under-test
});
assertThat(actual.getMessage(), is("..."));
@Test annotation no longer has an expected elementExpectedException rule but this is an experimental feature.This extension offers much the same features as JUnit4’s ExpectedException rule and is fully compatible with JUnit Jupiter’s extension model.
This extension is engaged by adding the @ExpectedException annotation to a test method. This annotation allows you to declare:
A description of the message which you expect to be in the exception thrown by this test method. Unlike JUnit4’s ExpectedException rule the message expectation does not accept a Hamcrest matcher so it is not quite as expressive as the equivalent JUnit4 rule however three different message matching strategies are supported:
messageIs: asserts that the exception message exactly matches the value you suppliedmessageStartsWith: asserts that the exception message starts with the value you suppliedmessageContains: asserts that the exception message contains the value you suppliedNote: these are all case sensitive.
@Test
@ExpectedException(type = Throwable.class)
public void canHandleAThrowable() throws Throwable {
throw new Throwable("...");
}
@Test
@ExpectedException(type = Throwable.class, messageIs = "Boom!")
public void canHandleAThrowable() throws Throwable {
throw new Throwable("Boom!");
}
@Test
@ExpectedException(type = RuntimeException.class, messageStartsWith = "Bye")
public void canHandleAnExceptionWithAMessageWhichStartsWith() {
throw new RuntimeException("Bye bye");
}
@Test
@ExpectedException(type = MyDomainException.class, messageContains = "sorry")
public void canHandleAnExceptionWithAMessageWhichContains() {
throw new MyDomainException("Terribly sorry old chap");
}
Notes:
Since usage of this extension implies that the developer expects an exception to be thrown the following test case will fail since it throws no exception:
@Test
@ExpectedException(type = Throwable.class)
public void failsTestForMissingException() {}
The expected exception type will match on the given type and on any subclasses of that type. In other words, the following test will pass:
@Test
@ExpectedException(type = Throwable.class, messageIs = "Boom!")
public void canHandleAThrowable() throws Throwable {
throw new Exception("Boom!");
}
This is for consistency with JUnit Jupiter, in which AssertThrows matches an exception type or any subclass of that exception type.