Exception Handling
JUnit Jupiter provides robust support for handling test exceptions. This includes the built-in mechanisms for managing test failures due to exceptions, the role of exceptions in implementing assertions and assumptions, and how to specifically assert non-throwing conditions in code.
Uncaught Exceptions
In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an extension and not caught within that test method, lifecycle method, or extension, the framework will mark the test or test class as failed.
|
Failed assumptions deviate from this general rule. In contrast to failed assertions, failed assumptions do not result in a test failure; rather, a failed assumption results in a test being aborted. See Assumptions for further details and examples. |
In the following example, the failsDueToUncaughtException() method throws an
ArithmeticException. Since the exception is not caught within the test method, JUnit
Jupiter will mark the test as failed.
private final Calculator calculator = new Calculator();
@Test
void failsDueToUncaughtException() {
// The following throws an ArithmeticException due to division by
// zero, which causes a test failure.
calculator.divide(1, 0);
}
It’s important to note that specifying a throws clause in the test method has
no effect on the outcome of the test. JUnit Jupiter does not interpret a throws clause
as an expectation or assertion about what exceptions the test method should throw. A test
fails only if an exception is thrown unexpectedly or if an assertion fails.
|
Failed Assertions
Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set
of assertion methods in the org.junit.jupiter.api.Assertions class, which throw
AssertionError when an assertion fails. This mechanism is a core aspect of how JUnit
handles assertion failures as exceptions. See the Assertions section for
further information about JUnit Jupiter’s assertion support.
Third-party assertion libraries may choose to throw an AssertionError to signal a
failed assertion; however, they may also choose to throw different types of exceptions to
signal failures. See also: Third-party Assertion Libraries.
|
JUnit Jupiter itself does not differentiate between failed assertions
(AssertionError) and other types of exceptions. All uncaught exceptions lead to a test
failure. However, Integrated Development Environments (IDEs) and other tools may
distinguish between these two types of failures by checking whether the thrown exception
is an instance of AssertionError.
|
In the following example, the failsDueToUncaughtAssertionError() method throws an
AssertionError. Since the exception is not caught within the test method, JUnit Jupiter
will mark the test as failed.
private final Calculator calculator = new Calculator();
@Test
void failsDueToUncaughtAssertionError() {
// The following incorrect assertion will cause a test failure.
// The expected value should be 2 instead of 99.
assertEquals(99, calculator.add(1, 1));
}
Asserting Expected Exceptions
JUnit Jupiter offers specialized assertions for testing that specific exceptions are
thrown under expected conditions. The assertThrows() and assertThrowsExactly()
assertions are critical tools for validating that your code responds correctly to error
conditions by throwing the appropriate exceptions.
Using assertThrows()
The assertThrows() method is used to verify that a particular type of exception is
thrown during the execution of a provided executable block. It not only checks for the
type of the thrown exception but also its subclasses, making it suitable for more
generalized exception handling tests. The assertThrows() assertion method returns the
thrown exception object to allow performing additional assertions on it.
@Test
void testExpectedExceptionIsThrown() {
// The following assertion succeeds because the code under assertion
// throws the expected IllegalArgumentException.
// The assertion also returns the thrown exception which can be used for
// further assertions like asserting the exception message.
IllegalArgumentException exception =
assertThrows(IllegalArgumentException.class, () -> {
throw new IllegalArgumentException("expected message");
});
assertEquals("expected message", exception.getMessage());
// The following assertion also succeeds because the code under assertion
// throws IllegalArgumentException which is a subclass of RuntimeException.
assertThrows(RuntimeException.class, () -> {
throw new IllegalArgumentException("expected message");
});
}
Using assertThrowsExactly()
The assertThrowsExactly() method is used when you need to assert that the exception
thrown is exactly of a specific type, not allowing for subclasses of the expected
exception type. This is useful when precise exception handling behavior needs to be
validated. Similar to assertThrows(), the assertThrowsExactly() assertion method also
returns the thrown exception object to allow performing additional assertions on it.
@Test
void testExpectedExceptionIsThrown() {
// The following assertion succeeds because the code under assertion throws
// IllegalArgumentException which is exactly equal to the expected type.
// The assertion also returns the thrown exception which can be used for
// further assertions like asserting the exception message.
IllegalArgumentException exception =
assertThrowsExactly(IllegalArgumentException.class, () -> {
throw new IllegalArgumentException("expected message");
});
assertEquals("expected message", exception.getMessage());
// The following assertion fails because the assertion expects exactly
// RuntimeException to be thrown, not subclasses of RuntimeException.
assertThrowsExactly(RuntimeException.class, () -> {
throw new IllegalArgumentException("expected message");
});
}
Asserting That no Exception is Expected
Although any exception thrown from a test method will cause the test to fail, there are
certain use cases where it can be beneficial to explicitly assert that an exception is
not thrown for a given code block within a test method. The assertDoesNotThrow()
assertion can be used when you want to verify that a particular piece of code does not
throw any exceptions.
@Test
void testExceptionIsNotThrown() {
assertDoesNotThrow(() -> {
shouldNotThrowException();
});
}
void shouldNotThrowException() {
}
Third-party assertion libraries often provide similar support. For example, AssertJ
has assertThatNoException().isThrownBy(() → …). See also:
Third-party Assertion Libraries.
|