什么是Mock单元测试?
在Java开发中,单元测试用于验证单个方法或类的行为是否符合预期。 当被测代码依赖外部服务(如数据库、网络接口、第三方API)时,直接调用这些依赖会带来不可控性和性能问题。 此时,Mock(模拟对象)技术就派上用场了 —— 它允许我们用可控的“假”对象替代真实依赖,从而专注于测试目标逻辑。
常用工具:Mockito + JUnit
在Java生态中,Mockito 是最流行的Mock框架,通常与 JUnit(单元测试框架)配合使用。
添加Maven依赖示例:
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
基本使用示例
假设有一个 UserService 依赖 UserRepository:
// 被测类
public class UserService {
private UserRepository repo;
public UserService(UserRepository repo) { this.repo = repo; }
public String getUserName(int id) {
User user = repo.findById(id);
return user != null ? user.getName() : "未知用户";
}
}
使用Mockito编写测试:
@Test
public void testGetUserName() {
// 创建Mock对象
UserRepository mockRepo = Mockito.mock(UserRepository.class);
// 定义Mock行为
Mockito.when(mockRepo.findById(1))
.thenReturn(new User(1, "张三"));
// 注入Mock并测试
UserService service = new UserService(mockRepo);
assertEquals("张三", service.getUserName(1));
}
最佳实践
- 只Mock外部依赖,不要Mock被测类本身
- 避免过度Mock,保持测试简洁可读
- 使用
@InjectMocks和@Mock注解简化代码(需配合MockitoJUnitRunner) - 验证交互:使用
verify()确保方法被正确调用
常见问题
Q:Mock能替代集成测试吗?
A:不能。Mock用于单元测试,集成测试仍需真实环境验证整体流程。
Q:如何Mock静态方法?
A:Mockito 3.4+ 支持 mockStatic(),但应谨慎使用,优先考虑重构代码以提高可测试性。