JUnit 5 的 assertThrows 方法可验证异常类型并获取异常实例用于进一步断言,比 @Test(expected = ...) 更灵活安全;它接收异常类和Executable代码块,返回异常对象,支持消息及字段校验,且作用域精确、语义清晰。
要验证一段业务代码是否如预期那样抛出了特定异常,JUnit 5 提供了
方法——它既能确认异常被抛出,又能获取异常实例用于进一步断言(比如检查异常消息、错误码等),比旧版的
更灵活、更安全。
基础用法:确认异常类型被抛出
最常用场景是检查某段逻辑是否在非法输入或状态时触发了目标异常:
传入一个
类型参数指定期望的异常类(如
)
第二个参数是函数式接口
,封装待测的“可能抛异常”的代码块
方法返回捕获到的异常对象,可用于后续校验
示例:
assertThrows(IllegalArgumentException.class, () -> userService.updateUser(null));
进阶断言:校验异常消息与字段
仅确认异常类型不够,业务中常需验证异常携带的提示信息或业务错误码是否准确。此时可先捕获异常,再对其属性做断言:
将
的返回值赋给变量,避免重复执行被测逻辑
用
检查
是否匹配预期文案
若自定义异常含
、
等字段,可直接调用 getter 断言
示例:
IllegalArgumentException e = assertThrows(IllegalArgumentException.class, () -> userService.updateUser(new User("", "123")));assertEquals("用户名不能为空", e.getMessage());
注意边界:避免误判和空指针
本身不处理“未抛异常”的情况——如果代码正常执行完毕,测试会直接失败(报错 “Expected java.lang.IllegalArgumentException to be thrown”)。但有两点易被忽略:
确保被测代码确实执行到了可能抛异常的路径(例如 if 分支、数据库连接失败模拟等),必要时配合 Mockito 打桩控制流程
不要对返回值为
的异常对象做链式调用(如
),应先确认异常非 null(
已保证不为 null,但自定义逻辑中仍需谨慎)
替代方案对比:为什么不用 @Test(expected = ...)
JUnit 4 的
注解存在明显局限:
只能声明异常类型,无法获取异常实例,不能校验消息或字段
只要测试方法中任意位置抛出该异常即算通过,哪怕发生在断言之后或清理逻辑里,容易掩盖真实问题
不支持 lambda 表达式,写法冗长,可读性差
而
将校验范围精确限定在你指定的代码块内,语义清晰,扩展性强,是当前推荐的标准做法。
assertThrows@Test(expected = ...)ClassIllegalArgumentException.classExecutableassertThrowsassertEqualse.getMessage()errorCodetimestampassertThrowsnulle.getMessage().contains(...)assertThrows@Test(expected = ...)assertThrows