一.Mockito是什么?
Mockito是一个用于Java单元测试的模拟框架。
它主要用于模拟对象和行为,在单元测试中隔离外部依赖,使得开发者能够专注于测试业务逻辑的正确性。
二.为什么要用Mockito?
因为Mockito是海量StackOverflow开发者社区评选出来的Java领域最佳模拟测试框架。
延伸:为什么要做单元测试?
单元测试的目的,是将应用程序的所有源代码,隔离成最小的可测试的单元,保证每个单元的正确性。理想情况下,如果每个单元都能保证正确,就能保证应用程序整体相当程度的正确性。
参考链接:为什么要单元测试-阿里云开发者社区
三.Mockito常用注解
1.@Mock
1.1 核心作用
创建一个虚拟的、完全模拟的对象。默认情况下,该对象的所有方法都不会执行真实逻辑,需要使用者通过打桩(Stub)的方式来定义其行为。
1.2 示例用法
public class Test {
// 方式1:默认创建
@Mock
private ArticleCalculator calculator;
// 方式2:指定Mock名称
@Mock(name = "database")
private ArticleDatabase dbMock;
// 方式3:设置默认应答行为
@Mock(answer = RETURNS_MOCKS)
private UserProvider userProvider; // 当方法返回对象类型时,自动返回mock对象而非null
// 方式4:添加额外接口
@Mock(extraInterfaces = {Queue.class, Observer.class})
private ArticleMonitor articleMonitor; // mock对象额外实现Queue和Observer接口
// 方式5:设置严格程度
@Mock(strictness = Mock.Strictness.LENIENT)
private ArticleConsumer articleConsumer; // 宽松模式,不必要的stub不会报错
// 方式6:仅打桩模式
@Mock(stubOnly = true)
private Logger logger; // 仅用于stub,不记录交互,无法进行verify验证
@Before
public void setUp() {
MockitoAnnotations.openMocks(this); // 初始化
}
}
1.3 注意事项
模拟对象是“空的”,默认返回 null、0 或 false
2.@Spy
2.1 核心作用
创建一个部分真实、部分模拟的对象。默认情况下,它会调用真实对象的逻辑,但允许开发者为特定的方法定义模拟行为。
2.2 示例用法
需要基于一个已存在的真实对象。
public class Test {
// 方式1:显式创建实例
@Spy
private Foo spyOnFoo = new Foo("参数");
// 方式2:Mockito自动创建
@Spy
private Bar spyOnBar; // Mockito会尝试调用无参构造器,即使是私有的
@Before
public void setUp() {
MockitoAnnotations.openMocks(this); // 初始化
}
}
2.3 注意事项
打桩方法的用法
List list = new LinkedList();
List spy = spy(list);
// ❌ 错误方式:会先调用真实方法,可能抛出异常
when(spy.get(0)).thenReturn("foo");
// ✅ 正确方式:使用doReturn系列方法
doReturn("foo").when(spy).get(0);
2.4 使用限制
- 不能实例化内部类、局部类、抽象类及接口
- 无法模拟和验证final方法
3.@InjectMocks
3.1 核心作用
用于自动注入依赖,支持快速注入 @Mock 和 @Spy 创建的对象。默认情况下,它会调用真实对象的逻辑。
3.2 示例用法
public class Test {
@Mock
private ArticleCalculator calculator;
@Mock(name = "database")
private ArticleDatabase dbMock;
@Spy
private UserProvider userProvider = new ConsumerUserProvider();
// 分别注入@Mock和@Spy标识的对象
@InjectMocks
private ArticleManager manager;
@Before
public void setUp() {
MockitoAnnotations.openMocks(this); // 初始化
}
}
3.3 注意事项
- Mockito 会按构造函数注入 → 属性setter注入 → 字段注入的顺序自动尝试注入依赖
- 如果注入失败,Mockito 不会报告错误,开发者需要自行检查依赖是否满足
- 只能注入使用 @Mock 和 @Spy 创建的模拟对象,如果字段是一个普通对象,@InjectMocks 将无法进行注入
- 不能实例化内部类、局部类、抽象类及接口
4.组合用法:@InjectMocks + @Spy
4.1 核心作用
用于调用真实逻辑但需要Mock外部依赖的情况。
4.2 示例用法
public class Test {
@Mock
private ArticleCalculator calculator;
@Mock(name = "database")
private ArticleDatabase dbMock;
@Spy
private UserProvider userProvider = new ConsumerUserProvider();
// 方式1:分别注入@Mock和@Spy标识的对象
@InjectMocks
private ArticleManager manager;
// 方式2:创建一个真实示例,并分别注入@Mock和@Spy标识的对象
@InjectMocks
@Spy
private ArticleManagerImpl manager;
@Before
public void setUp() {
MockitoAnnotations.openMocks(this); // 初始化
}
}
2052

被折叠的 条评论
为什么被折叠?



