You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java新手求教:如何使用Mockito编写JUnit测试?

Mockito与JUnit入门实践指南

一、Mockito的适用场景

  • 测试类依赖外部服务/复杂组件(如数据库连接、第三方API、耗时工具类)时,用Mock对象隔离依赖,避免测试时产生副作用(比如修改真实数据库数据)或难以初始化依赖。
  • 验证被测试类是否正确调用了依赖方法(包括调用次数、传入参数是否符合预期)。
  • 快速模拟异常场景:比如让依赖抛出指定异常,验证被测试类的异常处理逻辑。
  • 无需搭建完整依赖链,就能测试核心业务逻辑,提升测试效率。

二、JUnit测试基础编写规范

以JUnit 5为例,基础流程遵循Arrange-Act-Assert(准备-执行-断言)模式:

  1. 测试类命名:通常为被测试类名+Test,比如UserServiceTest。
  2. 测试方法:用@Test注解标记,方法名清晰描述测试场景,比如shouldReturnUserNameWhenUserIdIsValid。
  3. 核心步骤:
    • Arrange:初始化被测试对象、测试数据。
    • Act:调用被测试类的目标方法。
    • Assert:验证返回结果或状态是否符合预期。

纯JUnit测试示例:

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;

public class CalculatorTest {
    @Test
    public void shouldAddTwoNumbersCorrectly() {
        // Arrange
        Calculator calculator = new Calculator();
        int num1 = 7;
        int num2 = 3;
        
        // Act
        int result = calculator.add(num1, num2);
        
        // Assert
        assertEquals(10, result);
    }
}

三、Mockito核心用法

首先确保引入mockito-junit-jupiter依赖(适配JUnit 5),核心操作包括:

1. 创建Mock对象

  • 手动创建:用Mockito.mock()方法
    UserRepository mockRepo = Mockito.mock(UserRepository.class);
    
  • 注解自动注入:配合@ExtendWith(MockitoExtension.class)使用@Mock注解
    import org.junit.jupiter.api.extension.ExtendWith;
    import org.mockito.Mock;
    import org.mockito.junit.jupiter.MockitoExtension;
    
    @ExtendWith(MockitoExtension.class)
    public class UserServiceTest {
        @Mock
        private UserRepository userRepository; // 自动生成Mock对象
        
        private UserService userService;
    
        @BeforeEach
        void setUp() {
            userService = new UserService(userRepository); // 注入Mock依赖
        }
    }
    

2. 定义Mock对象的行为(Stubbing)

用when(模拟对象.方法(参数)).thenReturn(返回值)指定方法调用的返回结果:

// 当调用userRepository.findById(1L)时,返回预设的User对象
when(userRepository.findById(1L)).thenReturn(new User(1L, "Alice"));

模拟抛出异常:

when(userRepository.findById(2L)).thenThrow(new RuntimeException("User not found"));

3. 验证方法调用

用verify(模拟对象).方法(参数)验证被测试类是否正确触发了依赖方法:

// 验证userRepository.findById(1L)被调用了一次
verify(userRepository).findById(1L);

// 验证该方法从未被调用
verify(userRepository, never()).findById(3L);

// 验证方法被调用了恰好2次
verify(userRepository, times(2)).save(any(User.class));

四、Mockito+JUnit完整测试示例

假设我们有如下业务类:

// 被测试类
public class UserService {
    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public String getUserName(Long userId) {
        User user = userRepository.findById(userId);
        if (user == null) {
            throw new IllegalArgumentException("Invalid user ID");
        }
        return user.getName();
    }
}

// 依赖接口
public interface UserRepository {
    User findById(Long userId);
}

// 数据模型
public class User {
    private Long id;
    private String name;

    public User(Long id, String name) {
        this.id = id;
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

对应的测试类:

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
public class UserServiceTest {
    @Mock
    private UserRepository userRepository;

    @InjectMocks // 自动将@Mock对象注入到被测试类中
    private UserService userService;

    @Test
    public void shouldReturnUserNameWhenUserIdExists() {
        // Arrange
        Long validUserId = 1L;
        User mockUser = new User(validUserId, "Charlie");
        when(userRepository.findById(validUserId)).thenReturn(mockUser);

        // Act
        String userName = userService.getUserName(validUserId);

        // Assert
        assertEquals("Charlie", userName);
        verify(userRepository).findById(validUserId); // 验证依赖方法被正确调用
    }

    @Test
    public void shouldThrowExceptionWhenUserIdIsInvalid() {
        // Arrange
        Long invalidUserId = 99L;
        when(userRepository.findById(invalidUserId)).thenReturn(null);

        // Act & Assert
        IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
            userService.getUserName(invalidUserId);
        });
        assertEquals("Invalid user ID", exception.getMessage());
        verify(userRepository).findById(invalidUserId);
    }
}

五、初学者注意事项

  • 不要过度Mock:如果依赖是纯逻辑工具类,直接用真实对象测试更准确,Mock只用于复杂或有副作用的依赖。
  • 单一测试场景:每个测试方法只验证一个逻辑点,方法名要直观描述测试内容。
  • 启用静态导入:导入static org.mockito.Mockito.*,让测试代码更简洁。

内容的提问来源于stack exchange,提问作者User1515

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 03:56:11