assertthrowsexactly用于精确断言抛出指定异常类(非子类)的工具方法,要求实际异常必须是参数中确切类的实例,支持泛型擦除后的原始类型匹配,并需接收返回值以进一步校验。

在 JUnit5 中,assertThrowsExactly 是专门用于**精确断言抛出指定异常类(含类型和泛型擦除后的一致性)**的工具方法,特别适合验证业务异常是否按预期被 throw 抛出。
明确 assertThrowsExactly 的核心作用
它要求实际抛出的异常对象必须是参数中指定的**确切类(class)实例**,不能是其子类(这点和 assertThrows 不同)。比如你 throw new UserNotFoundException(),就必须用 UserNotFoundException.class 去匹配,用其父类 RuntimeException.class 会失败。
基本用法:捕获并验证异常类型
直接传入异常类和待执行的函数式代码块即可:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
<pre class="brush:php;toolbar:false;">import static org.junit.jupiter.api.Assertions.*;
@Test
void whenUserNotFound_thenThrowUserNotFoundException() {
// 假设 service.findById(999) 会 throw new UserNotFoundException("user not found")
UserNotFoundException exception = assertThrowsExactly(
UserNotFoundException.class,
() -> service.findById(999)
);
// 可选:进一步断言异常消息
assertEquals("user not found", exception.getMessage());
}
注意泛型异常类的类型擦除问题
Java 泛型在运行时被擦除,所以像 throw new BusinessException<string>("msg")</string>
assertThrowsExactly(BusinessException.class, ...) 是合法的;但 assertThrowsExactly(BusinessException<string>.class, ...)</string> 编译不通过 —— 因为泛型类字面量不存在。只需断言原始类型即可。
常见错误与规避方式
-
误用子类去匹配:如抛出
ValidationException,却用RuntimeException.class断言 → 改用ValidationException.class -
忘记接收返回值:
assertThrowsExactly返回异常实例,不接收会导致无法校验消息或字段 → 声明变量接收 -
lambda 中未真正触发异常:确保调用链中确实执行了
throw,比如方法被 mock 返回正常值 → 检查 mock 行为或真实逻辑路径
不复杂但容易忽略细节,关键是记住“精确类名 + 接收异常实例 + 避开泛型字面量”。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










