1. 概述
在这个教程中,我们将讨论如何使用依赖注入将Mockito模拟对象插入Spring Bean进行单元测试。在实际应用中,当组件经常需要访问外部系统时,提供适当的隔离测试至关重要,这样我们就能专注于测试单个单元的功能,而无需在每次测试中都牵涉到整个类层次结构。
注入mock是实现这种隔离的一种清晰方式。
2. Maven 依赖
为了单元测试和模拟对象,我们需要以下Maven依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.12.0</version>
</dependency>
我们在这个示例中选择了Spring Boot,但经典的Spring同样适用。
3. 编写测试
3.1. 业务逻辑
首先,创建一个我们将要测试的简单服务:
@Service
public class NameService {
public String getUserName(String id) {
return "Real user name";
}
}
然后将其注入到UserService
类中:
@Service
public class UserService {
private NameService nameService;
@Autowired
public UserService(NameService nameService) {
this.nameService = nameService;
}
public String getUserName(String id) {
return nameService.getUserName(id);
}
}
对于这篇文章,提供的类无论提供什么id,都会返回一个名字。这样做是为了避免测试复杂逻辑而分心。
我们还需要一个标准的Spring Boot主类,用于扫描bean并初始化应用程序:
@SpringBootApplication
public class MocksApplication {
public static void main(String[] args) {
SpringApplication.run(MocksApplication.class, args);
}
}
3.2. 测试逻辑
现在转向测试逻辑。首先,我们必须配置测试的应用上下文:
@Profile("test")
@Configuration
public class NameServiceTestConfiguration {
@Bean
@Primary
public NameService nameService() {
return Mockito.mock(NameService.class);
}
}
@Profile
注解告诉Spring只有在“test”配置活跃时才应用此配置。@Primary
注解确保在自动装配时使用这个实例而不是真实实例。方法本身创建并返回我们的NameService
类的Mockito模拟。
接下来我们可以编写单元测试:
@ActiveProfiles("test")
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = MocksApplication.class)
public class UserServiceUnitTest {
@Autowired
private UserService userService;
@Autowired
private NameService nameService;
@Test
public void whenUserIdIsProvided_thenRetrievedNameIsCorrect() {
Mockito.when(nameService.getUserName("SomeId")).thenReturn("Mock user name");
String testName = userService.getUserName("SomeId");
Assert.assertEquals("Mock user name", testName);
}
}
我们使用@ActiveProfiles
注解启用“test”配置,并激活我们之前编写的模拟配置。结果,Spring为UserService
类自动装配一个真实实例,但对于NameService
类则是模拟对象。测试本身是一个典型的JUnit+Mockito测试。我们配置模拟对象的行为,然后调用我们想要测试的方法,并断言其返回我们期望的值。
也可以(尽管不推荐)避免在这样的测试中使用环境配置。要做到这一点,可以移除@Profile
和@ActiveProfiles
注解,并在UserServiceTest
类上添加@ContextConfiguration(classes = NameServiceTestConfiguration.class)
注解。
4. 总结
在这篇简短的文章中,我们学习了如何轻松地将Mockito模拟对象注入到Spring Bean中。
如往常一样,所有代码示例可在GitHub上找到。