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.