junit 5 中 assertthrows 异常测试核心是“验证抛出+获取实例+深度校验”:需传入具体异常类与触发异常的lambda,返回异常实例用于消息、业务字段等精准断言;assertthrows允许子类匹配,assertthrowsexactly要求严格类型一致。

JUnit 5 中用 assertThrows 做异常测试,核心是“验证抛出 + 获取实例 + 深度校验”,而不是单纯看有没有异常。
断言指定异常类型并获取实例
这是最基础也最关键的一步:确保被测代码在特定条件下确实抛出了你期望的异常类型,并拿到这个异常对象用于后续检查。
-
assertThrows第一个参数必须是具体的异常类(如IllegalArgumentException.class),不能只写父类(比如用RuntimeException.class代替子类)——虽然语法通过,但会降低测试精度 - 第二个参数是一个 lambda 表达式,里面必须**真实调用被测方法**,且该调用在运行时会触发异常;写成
() -> someMethod(没括号)或把异常构造写在 lambda 外,都会导致测试失败 - 返回值就是实际抛出的异常对象,可直接赋值给变量,避免重复执行逻辑
验证异常消息是否符合预期
只确认类型还不够,业务异常通常携带关键提示信息,需要进一步比对。
- 用
assertEquals("预期文案", exception.getMessage())校验完整消息 - 用
assertTrue(exception.getMessage().contains("关键词"))检查子串是否存在 - 对复杂格式(如带时间戳、ID 的消息),可用
Pattern.compile("正则").matcher(exception.getMessage()).matches()进行匹配
检查自定义异常的业务字段
如果抛出的是自定义异常(如 InsufficientBalanceException),往往还包含错误码、状态码等字段,这些也要一并验证。
- 先用
assertThrows捕获异常实例 - 再调用其 getter 方法,比如
exception.getErrorCode()或exception.getHttpStatus() - 配合
assertEquals或assertThat(如用 AssertJ)做断言
区分 assertThrows 和 assertThrowsExactly
两者都用于捕获异常,但语义不同:
-
assertThrows(Class<t>, Executable)</t>允许子类匹配(比如期望IllegalArgumentException,实际抛出NumberFormatException也能通过) -
assertThrowsExactly(Class<t>, Executable)</t>要求**严格匹配**,连子类都不接受,适合对异常类型有强约束的场景 - 日常多数情况用
assertThrows即可;只有明确禁止子类时,才换用assertThrowsExactly











