JUnit 5 assertThrows: Verify Exceptions with a Simple Example
Learn how to use JUnit 5's assertThrows to verify exceptions, see a concrete code example, and avoid common pitfalls.
23 Aug 2025, 19:39 UTC

Use assertThrows to verify that a specific exception is thrown
When a method must fail because of an illegal condition, the simplest way to confirm the failure is to check that the expected exception is thrown. JUnit 5 provides the static method assertThrows for exactly this purpose.
How it works
assertThrows lives in org.junit.jupiter.api.Assertions. Its signature is:
public static T assertThrows(Class expectedException, Executable lambda, Object... arguments)
The first argument is the exact exception class (or a subclass) that you expect. The second argument is a lambda that executes the code under test. If the lambda throws the expected exception, the method returns the caught exception object, allowing you to inspect its message, cause, or other properties. If no exception is thrown, or a different exception type appears, the test fails.
Concrete code example
Consider a simple utility class that validates its arguments:
class Calculator {
int divide(int a, int b) {
if (b == 0) {
throw new IllegalArgumentException("Divisor must not be zero");
}
return a / b;
}
}
The corresponding test uses assertThrows to verify both the exception type and its message:
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class CalculatorTest {
@Test
void shouldThrowWhenDivisorZero() {
Calculator calc = new Calculator();
// The lambda executes the code that may throw
IllegalArgumentException ex = assertThrows(
IllegalArgumentException.class, // expected type
() -> calc.divide(5, 0), // code to run
"Divisor must not be zero" // optional message check
);
// Further inspection of the exception
assertEquals("Divisor must not be zero", ex.getMessage());
}
}
Running this test with Maven or Gradle (e.g., mvn test or gradle test) will pass if the exception is thrown and the message matches; otherwise the test fails, alerting you to a logic error.
Typical pitfalls
- Exact class requirement:
assertThrowschecks the thrown class against the supplied expectedException. Passing a subclass of the expected type works only if the subclass is assignable to the expected class. Using a superclass may cause false positives. - Placement matters: The call must be inside a
@Testmethod. Putting it in@BeforeEachor@BeforeAllcan cause the exception to be swallowed by the test lifecycle, leading to nondeterministic results. - Checked exceptions: The lambda must either handle or declare the checked exception.
assertThrowsdoes not automatically wrap checked exceptions; you need to wrap them in a lambda that throws a RuntimeException or declare the checked exception in the method signature.
Verification steps
- Create a class with a method that throws the expected exception (e.g.,
IllegalArgumentException). - Write a
@Testmethod that callsassertThrowswith the exact class and a lambda that invokes the method. - Run the suite with Maven (
mvn test) or Gradle (gradle test) using JUnit 5. - Inspect the console output: a passing test shows no failure, while a failing test prints the mismatch between the expected and actual exception type or message.
Limitations and common mistakes
While assertThrows is powerful, it does not verify every aspect of the failure. It only confirms that the specified exception type is thrown; it does not check stack‑trace depth, thread context, or the exact line number. For complex scenarios you may need additional assertions on the caught exception (e.g., assertEquals on getMessage() or getCause()).
Common mistakes include:
- Using a subclass of the expected exception instead of the exact class, which can mask subtle type mismatches.
- Placing
assertThrowsin a@BeforeEachmethod; the test framework may treat the exception as part of the setup phase, causing the test to be marked as failed even though the production code behaved correctly. - Assuming that checked exceptions are automatically caught; remember to wrap or declare them in the lambda.
Practical way to check the result
After running the test, verify two things:
- The test report indicates “Tests passed” (or “0 failures”).
- The exception message (if you supplied a message check) appears in the failure output when the assertion does not match, confirming that the message was evaluated lazily (especially useful when the message construction is expensive).
Conclusion
assertThrows provides a concise, expressive way to assert that a piece of code fails with the exact exception you expect. By returning the caught exception, it enables fine‑grained validation of message, cause, or custom properties, reducing boilerplate compared to manual try‑catch blocks. Remember to use the exact exception class, keep the call inside a @Test method, and supplement the assertion with additional checks when deeper verification is required. Following these guidelines helps you write reliable, maintainable JUnit 5 tests that catch regressions early.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.