Mockito

1.什么是Mockito?

Mockito 是一个强大的 Java 测试框架,专门用于创建和管理模拟对象。它允许我们:

  • 创建模拟对象:通过简单的语法创建对象的模拟版本。
  • 定义行为:设置模拟对象的方法返回值或抛出异常。
  • 验证交互:验证某些方法是否被调用,或调用了几次。

1.1Mockito的核心功能

  • 模拟(Mocking):创建一个类或接口的模拟对象。
  • 桩方法(Stubbing):定义模拟对象的方法行为,例如返回特定值或抛出异常。
  • 验证(Verification):检查模拟对象的方法是否按照预期被调用。

2.引入Mockito

要在项目中使用 Mockito,我们首先需要在 pom.xml 中添加其依赖:

java 复制代码
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>4.0.0</version>
    <scope>test</scope>
</dependency>

3.一个简单的Mockito测试

例:银行转账服务

我们有一个银行转账服务 TransferService,它依赖于一个账户服务 AccountService 来完成实际的资金转移。在测试转账功能时,我们不希望真的去修改账户中的金额,因此可以使用 Mockito 来模拟 AccountService。

被测试类 TransferService.java:

java 复制代码
public class TransferService {

    private AccountService accountService;

    public TransferService(AccountService accountService) {
        this.accountService = accountService;
    }

    public boolean transfer(String fromAccount, String toAccount, double amount) {
        if (accountService.withdraw(fromAccount, amount)) {
            return accountService.deposit(toAccount, amount);
        }
        return false;
    }
}

依赖类 AccountService.java:

java 复制代码
public interface AccountService {
    boolean withdraw(String account, double amount);
    boolean deposit(String account, double amount);
}

测试类 TransferServiceTest.java:

java 复制代码
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;

import static org.junit.Assert.*;
import static org.mockito.Mockito.*;

public class TransferServiceTest {

    private AccountService accountService;
    private TransferService transferService;

    @Before
    public void setUp() {
        accountService = Mockito.mock(AccountService.class); // 创建AccountService的模拟对象
        transferService = new TransferService(accountService); // 传入模拟对象
    }

    @Test
    public void testTransferSuccess() {
        when(accountService.withdraw("123", 100.0)).thenReturn(true); // 设置 withdraw 方法的返回值
        when(accountService.deposit("456", 100.0)).thenReturn(true);   // 设置 deposit 方法的返回值

        boolean result = transferService.transfer("123", "456", 100.0);

        assertTrue(result); // 断言转账成功
        verify(accountService).withdraw("123", 100.0); // 验证 withdraw 方法被调用
        verify(accountService).deposit("456", 100.0);  // 验证 deposit 方法被调用
    }

    @Test
    public void testTransferFailure() {
        when(accountService.withdraw("123", 100.0)).thenReturn(false); // 模拟 withdraw 失败

        boolean result = transferService.transfer("123", "456", 100.0);

        assertFalse(result); // 断言转账失败
        verify(accountService).withdraw("123", 100.0); // 验证 withdraw 被调用
        verify(accountService, never()).deposit(anyString(), anyDouble()); // 验证 deposit 没有被调用
    }
}

解释:

  1. 创建模拟对象 :使用 Mockito.mock(AccountService.class) 创建 AccountService
    的模拟对象。
  2. 设置桩方法 :通过 when(...).thenReturn(...) 方法,定义模拟对象的方法返回特定值。例如:当
    withdraw 方法被调用时,返回 true。
  3. 验证交互 :使用 verify(...) 来验证特定方法是否被调用,以及调用次数。在
    testTransferSuccess 中,我们验证了 withdraw 和 deposit 方法都被正确调用。

4.Mockito常用功能

4.1模拟异常

在测试错误处理逻辑时,模拟方法抛出异常也很有用。Mockito 提供了 thenThrow() 来模拟异常行为。

java 复制代码
@Test(expected = RuntimeException.class)
public void testWithdrawThrowsException() {
    when(accountService.withdraw("123", 100.0)).thenThrow(new RuntimeException("Insufficient funds"));
    
    transferService.transfer("123", "456", 100.0);
}

4.2参数匹配

Mockito 提供了多种参数匹配器,用于更加灵活地模拟方法。例如:

  • anyString():匹配任意字符串。
  • anyDouble():匹配任意 double 类型参数。
  • eq(value):匹配指定的值。
java 复制代码
when(accountService.deposit(anyString(), eq(100.0))).thenReturn(true);

4.3验证调用次数

可以验证方法是否被调用了指定次数:

java 复制代码
verify(accountService, times(1)).withdraw("123", 100.0); // 验证 withdraw 方法被调用一次

4.4重置模拟对象

有时需要重置模拟对象的状态,Mockito 提供了 reset() 方法:

java 复制代码
verify(accountService, times(1)).withdraw("123", 100.0); // 验证 withdraw 方法被调用一次

4.5重置模拟对象

有时我们需要重置模拟对象的状态,Mockito 提供了 reset() 方法:

java 复制代码
reset(accountService);

有兴趣的小伙伴可以关注我的公众号【知识星球站】一起讨论学习!!

独自行走江湖路,心怀壮志闯天涯。

相关推荐
鬼手点金2 小时前
带工具调用的多轮交互:Agent 的核心循环
服务器·人工智能·windows·深度学习·microsoft·机器学习·交互
Navicat中国19 小时前
Navicat 18 支持 Azure OpenAI 接入,合规 AI 赋能 SQL 开发
数据库·人工智能·microsoft·ai·azure·navicat·数据
张张123y1 天前
2026 Agent 框架怎么选?拆 3 层底层逻辑(运行循环 / 记忆 / 工具协议)+ 一张决策表
linux·ubuntu·microsoft·langgraph·mcp·crewai·agent 框架
霍格沃兹测试学院-小舟畅学1 天前
Playwright CLI:语义快照与局部检索,AI 如何找到正确的页面元素?
人工智能·microsoft
某不知名網友2 天前
ROS2进阶:服务通信、自定义SRV接口、参数服务器与基于服务的参数通信详解
java·开发语言·microsoft
不爱学英文的码字机器2 天前
从Q1迁到T1,同一个编号已经换了含义
前端·数据库·microsoft
龙亘川2 天前
城市公共安全治理如何从“人海战术“走向“数据驱动“?
大数据·数据库·人工智能·安全·microsoft·智慧城市·数据可视化
2503_931712482 天前
数据服务公司怎么帮助企业更高效找到行业数据与商业情报
大数据·人工智能·microsoft
多看书少吃饭3 天前
使用 Qwen 实现实时语音、视频聊天与屏幕共享:原理、接入流程与工程实践
microsoft·音视频
奈落243 天前
Anthropic 收购 Vercept:Claude 的“计算机使用”要补感知与交互这一课,团队该盯什么
microsoft·api·agent·ai 编程