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);

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

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

相关推荐
MinIO官方账号20 小时前
使用 Kafka 和 MinIO 实现人工智能数据工作流
人工智能·microsoft·kafka
猿大师办公助手1 天前
如何用猿大师办公助手实现OA系统中Word公文/合同在线编辑及流转?
chrome·microsoft·word
幽默小书生2 天前
基于.NET 8.0,C#中Microsoft.Office.Interop.Excel来操作office365的excel
microsoft·c#·excel
竹之却2 天前
Word中Normal.dotm样式模板文件
microsoft·word
学习嵌入式的小羊~3 天前
linux驱动—在自己的总线目录下创建属性文件
linux·windows·microsoft
小奥超人3 天前
word技巧:如何禁止复制word文件内容?
windows·经验分享·microsoft·word·办公技巧
时光追逐者3 天前
一个基于.NET8+WPF开源的简单的工作流系统
开发语言·microsoft·c#·asp.net·.net·wpf·.netcore
MicrosoftReactor3 天前
技术速递|Microsoft.Extensions.AI 预览版简介 – 适用于 .NET 的统一 AI 构建块
人工智能·microsoft·.net
Starshime4 天前
【Java】LinkedList实现类的使用
windows·microsoft
OldGj_4 天前
【设计模式七大设计原则】
windows·microsoft