Historically, assertions against an exception thrown by a JUnit test case involved one of the following:

  1. Wrap the test case code in a try/fail/catch idiom
  2. Use the expected element of the @Test annotation
  3. Use JUnit4’s ExpectedException rule

In JUnit5:

  1. The wrap-and-assert approach now has some lambda sugar, for example:

    RuntimeException actual = assertThrows(RuntimeException.class, () -> {
        // code-under-test
    assertThat(actual.getMessage(), is("..."));
  2. The @Test annotation no longer has an expected element
  3. The limited support for JUnit4 rules on JUnit5 does support the ExpectedException 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:

Note: these are all case sensitive.


Expect a Throwable, with no expectation on the exception message
@ExpectedException(type = Throwable.class)
public void canHandleAThrowable() throws Throwable {
    throw new Throwable("...");
Expect a Throwable with an exact match on the exception message
@ExpectedException(type = Throwable.class, messageIs = "Boom!")
public void canHandleAThrowable() throws Throwable {
    throw new Throwable("Boom!");
Expect a RuntimeException with an match on the beginning of the exception message
@ExpectedException(type = RuntimeException.class, messageStartsWith = "Bye")
public void canHandleAnExceptionWithAMessageWhichStartsWith() {
    throw new RuntimeException("Bye bye");
Expect a custom exception type with an match on any part of the exception message
@ExpectedException(type = MyDomainException.class, messageContains = "sorry")
public void canHandleAnExceptionWithAMessageWhichContains() {
    throw new MyDomainException("Terribly sorry old chap");


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:

@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:

@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.