JUnit 5 的 assertThrows 是验证自定义异常最推荐的方式,它能确认异常类型并获取异常实例以逐字段断言 errorCode、message 等,比 @Test(expected = ...) 更强大安全,且需注意避免链式调用空指针及确保异常真实触发。

JUnit 5 的 assertThrows 是验证自定义异常最推荐的方式,它不仅能确认异常类型被抛出,还能直接拿到异常实例,进而断言 errorCode、message 等字段——这比旧版 @Test(expected = ...) 强大得多。
获取异常对象后逐字段断言
先用 assertThrows 捕获异常,再对它的各个属性做独立校验。这是最清晰、最安全的做法:
- 调用
assertThrows(YourException.class, () -> yourMethod()),返回值赋给变量(如e) - 用
assertEquals("ERR_001", e.getErrorCode())校验错误码 - 用
assertEquals("用户名不能为空", e.getMessage())校验提示文案 - 如果异常有嵌套原因(
getCause()),也可继续断言其类型或消息
避免链式调用引发空指针
assertThrows 保证返回非 null 的异常对象,但如果你后续自己写了额外逻辑(比如条件判断后再取字段),仍需注意判空。更稳妥的写法是:
- 不写
e.getMessage().contains("xxx")这类可能因getMessage()返回 null 而崩溃的链式调用 - 改用
assertTrue(e.getMessage() != null && e.getMessage().contains("xxx")) - 或先断言消息非空:
assertNotNull(e.getMessage()),再断言内容
确保测试路径真实触发异常
异常没抛出来,测试会直接失败;但更隐蔽的问题是:代码看似执行了,却因分支未进入、Mock 未生效等原因“绕过”了抛异常逻辑。建议:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
立即学习“Java免费学习笔记(深入)”;
- 检查业务方法中抛异常的条件是否真被满足(例如传入 null、负数、非法字符串)
- 若涉及外部依赖(如数据库、HTTP 调用),用 Mockito 打桩让其明确抛出自定义异常
- 必要时加日志或调试断点,确认执行流确实走到 throw 语句那一行
完整示例(含自定义异常)
假设你有这样一个异常:
public class ValidationException extends RuntimeException {private final String errorCode;
public ValidationException(String message, String errorCode) {
super(message);
this.errorCode = errorCode;
}
public String getErrorCode() { return errorCode; }
}
对应测试可写成:
@Testvoid whenEmptyUsername_thenThrowValidationException() {
ValidationException e = assertThrows(ValidationException.class,
() -> userService.create(new User("", "123")));
assertEquals("USR_001", e.getErrorCode());
assertEquals("用户名不能为空", e.getMessage());
}

















