When writing unit tests, it makes sense to check whether certain methods throw the expected exceptions when we supply invalid inputs or pre-conditions that are not satisfied. Junit 5 provides the following assertion methods for handling test exceptions. These method names are self-explanatory enough to suggest their usage. Please continue reading for a deeper understanding.
Method | Description |
---|---|
assertThrows() | Verifies that a particular type of exception (or its subclass) is thrown. The test passes if the exception is thrown and fails otherwise. |
assertThrowsExactly() | Verifies that only an exact type of exception is thrown. The test passes if the exception is thrown and fails otherwise. |
assertDoesNotThrow() | Asserts that the test block does not throw any exception. |
The following quick reference snippet shows how to use these methods:
@Test
void testExpectedException() {
// 1. assertThrows() checks for RuntimeException or its subclass ( i.e. IllegalArgumentException)
// This "PASSES" because IllegalArgumentException extends RuntimeException
ApplicationException thrown = Assertions.assertThrows(RuntimeException.class, () -> {
// ... Code under test ...
throw new IllegalArgumentException("custom error message");
});
Assertions.assertEquals("custom error message", thrown.getMessage());
// 2. assertThrowsExactly() checks exactly for RuntimeException only
// This "FAILS" because assertion expects only RuntimeException instance
RuntimeException thrown = Assertions.assertThrowsExactly(RuntimeException.class, () -> {
// ... Code under test ...
throw new IllegalArgumentException("expected message");
}
//3. assertDoesNotThrow() should not see any exception
assertDoesNotThrow(() -> {
// ... Code under test ...
});
}
1. JUnit assertThrows() API
The assertThrows()
method verifies that a particular type of exception (or any of its subclasses) is thrown when a code block is executed.
1.1. Method Syntax
The assertThrows()
method asserts that execution of the supplied executable block or lambda expression throws an exception of the expectedType
. It is an overloaded method and takes the following parameters.
static <T extends Throwable>T assertThrows(Class<T> expectedType, Executable executable)
static <T extends Throwable>T assertThrows(Class<T> expectedType, Executable executable, String message)
static <T extends Throwable>T assertThrows(Class<T> expectedType, Executable executable, Supplier<String> messageSupplier)
expectedType
– Test code is expected to throw an exception of this type.message
– If the executable code does not throw any exception, this message will be printed along with the FAIL result.-
messageSupplier
– The message will be retrieved from it in case the test fails.
1.2. Matches Specified Exception or Its Child Exception
The assertThrows()
will FAIL:
- If no exception is thrown from the
executable
block - If an exception of a different type is thrown
For example, in below example "1"
is a valid number so no exception will be thrown. This test will fail with the message in the console.
@Test
void testExpectedExceptionFail() {
NumberFormatException thrown = Assertions.assertThrows(NumberFormatException.class, () -> {
Integer.parseInt("1");
}, "NumberFormatException error was expected");
}

The assertThrows()
will PASS:
- If the code block throws an exception of the specified type or a subtype.
- For example, if we are expecting
IllegalArgumentException
and the test throwsNumberFormatException
then also the test willPASS
because NumberFormatException extends IllegalArgumentException class.
Note that if we pass Exception.class as the expected exception type, any exception thrown from the executable block will make the assertion PASS since Exception is the super-type for all exceptions.
Given below is a straightforward test that expects NumberFormatException
to be thrown when the supplied code block is executed.
@Test
void testExpectedException() {
NumberFormatException thrown = Assertions.assertThrows(NumberFormatException.class, () -> {
Integer.parseInt("One");
}, "NumberFormatException was expected");
Assertions.assertEquals("For input string: \"One\"", thrown.getMessage());
}
@Test
void testExpectedExceptionWithParentType() {
Assertions.assertThrows(IllegalArgumentException.class, () -> {
Integer.parseInt("One");
});
}
- In
testExpectedException
, The executable code isInteger.parseInt("One")
which throwsNumberFormatException
if method argument is not a valid numeric number. TheassertThrows()
the method expects – so this exception so the test result isPASS
. - In
testExpectedExceptionWithParentType
, we are executing the same code but this time we are exceptingIllegalArgumentException
which is the parent ofNumberFormatException
. This test also passes.
2. JUnit assertThrowsExactly() API
The assertThrowsExactly()
method is similar to assertThrows()
, but it verifies that only the exact type of exception specified is thrown, and not any subclass.
Let’s modify the previous test testExpectedExceptionWithParentType(). It was PASS with assertThrows() method. When we match the exact exception type, then it should fail.
// FAIL with assertThrowsExactly()
// PASS with assertThrows()
@Test
void testExpectedExceptionWithParentType() {
Assertions.assertThrowsExactly(IllegalArgumentException.class, () -> {
Integer.parseInt("One");
});
}
3. JUnit assertDoesNotThrow()
The assertDoesNotThrow() method verifies that the block of code throws no exception. This is useful when we want to ensure that our code runs smoothly without any issues and can handle edge-cases such as negative inputs etc.
@Test
void testDivideDoesNotThrowException() {
// Verify that user is created when input contains allowed patterns
assertDoesNotThrow(() -> addUser(new User(...)));
}
4. Expected Exception @Rule in JUnit 4
In JUnit 4, we can use the @Rule
annotation along with ExpectedException
to assert exceptions. The following class rewrites the previous example in JUnit 4 syntax.
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
public class MyTestClass {
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Test
public void testExpectedException() {
expectedException.expect(NumberFormatException.class);
expectedException.expectMessage("For input string: \"One\"");
Integer.parseInt("One");
}
@Test
public void testExpectedExceptionWithParentType() {
expectedException.expect(IllegalArgumentException.class);
Integer.parseInt("One");
}
}
Happy Learning !!
Comments