验证java方法异常的核心是确认抛出指定类型及消息的异常,junit 5推荐用assertthrows捕获并断言类型与消息,assertdoesnotthrow确保合法输入不抛异常,避免使用junit 4过时的expected属性。

验证 Java 方法是否抛出预期异常,核心是让测试代码“主动触发”非法路径,并确认它确实按设计抛出了指定类型(甚至指定消息)的异常。JUnit 提供了多种可靠方式,关键不在于“有没有异常”,而在于“是不是那个异常”。
用 assertThrows 捕获并断言异常类型
这是 JUnit 5 推荐的标准做法,简洁、语义清晰、支持 Lambda 表达式。
- 调用 assertThrows(异常类.class, 可执行代码),如果代码块抛出该类型异常,测试通过;否则失败
- 返回值是捕获到的异常对象,可进一步校验其消息、状态等
- 示例:验证负数阶乘抛出 IllegalArgumentException
若还需检查异常消息,可接着用 assertEquals:
assertEquals("Input cannot be negative", thrown.getMessage());用 try-catch + fail 做细粒度校验
适用于 JUnit 4 或需要深度验证异常细节(如嵌套异常、错误码、字段值)的场景。
- 在 try 块中执行被测方法
- 正常情况下不应走到 catch —— 所以 catch 到异常后做断言,没 catch 到就调用 fail() 强制失败
- 能直接拿到异常实例,适合做多维度断言(消息、cause、stack trace 等)
service.process(null);
fail("Expected NullPointerException");
} catch (NullPointerException e) {
assertNotNull(e.getMessage());
assertTrue(e.getMessage().contains("name"));
}
验证“不该抛异常”的情况:assertDoesNotThrow
很多测试容易忽略“成功路径”——即输入合法时必须静默执行,不能抛任何异常。
- 使用 assertDoesNotThrow(() -> method()) 明确表达“这个调用必须成功”
- 比空 try-catch 更安全,避免漏写 fail 或逻辑错位
- 特别适合 void 方法或只产生副作用(如发消息、改状态)的场景
避免过时或易错方式
@Test(expected = XxxException.class) 是 JUnit 4 的写法,虽仍可用,但有明显缺陷:
- 无法校验异常消息,也无法获取异常对象做后续断言
- 只要方法中任意位置(包括 setup 或 teardown)抛出该异常,测试就通过,掩盖真实问题
- 不支持组合断言,灵活性差
新项目统一优先使用 assertThrows / assertDoesNotThrow。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











