正确做法是用when(...).thenThrow(...)模拟有返回值方法抛异常,void方法必须用doThrow(...).when(...).method();需确保调用的是mock对象而非真实实例,静态/final/private方法需借助mockito-inline等增强工具。

在 Java 单元测试中,用 Mockito 模拟方法抛出指定异常,核心是使用 when(...).thenThrow(...) 语法。只要目标方法是被 mock 的对象(非真实实例),就能精准控制它在调用时抛出你指定的异常。
确保被测方法调用的是 mock 对象
Mockito 只能控制 mock 出来的对象行为。如果误用了真实对象(比如 new 出来的实例或 Spring 自动注入的 bean 未被正确替换),thenThrow 不会生效。
- 用
Mockito.mock(YourClass.class)创建 mock 实例 - 或用
@Mock注解配合@ExtendWith(MockitoExtension.class)(JUnit 5) - 确保被测代码中实际调用的是这个 mock 对象,而不是 new 出来的或容器管理的真实 bean
基本写法:模拟单个异常
对某个方法调用,直接抛出一个异常实例或 Class:
Service service = mock(Service.class);
when(service.doSomething()).thenThrow(new RuntimeException("模拟失败"));
// 或者更简洁地传入异常类(会自动实例化无参构造)
when(service.doSomething()).thenThrow(IllegalArgumentException.class);
// 也可以抛出多个异常(按调用顺序依次抛出)
when(service.doSomething()).thenThrow(IOException.class, NullPointerException.class);
验证异常是否被正确抛出
推荐用 JUnit 5 的 assertThrows 显式断言异常类型和消息:
立即学习“Java免费学习笔记(深入)”;
Exception exception = assertThrows(RuntimeException.class, () -> {
targetObject.process(); // 触发被 mock 方法
});
assertEquals("模拟失败", exception.getMessage());
避免只用 try-catch + fail,那样无法保证异常类型准确,也不够简洁。
注意不能 mock 的情况
以下情况 thenThrow 无效,需换思路:
- 静态方法、final 方法、private 方法 —— Mockito 默认不支持(需用
mockito-inline或PowerMock等增强工具) - 对真实对象(
spy)调用未 stub 的方法时,默认执行原逻辑 —— 若想让它抛异常,必须显式when(spy.method()).thenThrow(...) - 构造器或字段初始化阶段就抛异常 —— 这发生在 mock 创建前,Mockito 无法干预,应考虑重构或用
MockitoSession配合自定义 Answer


















