Mockito学习笔记

一.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); // 初始化
    }
}

四.文档

1.官方文档

2.参考文档

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值