Mockito 模拟注入 Spring Bean
1. 概述
在本教程中,我们将讨论如何使用依赖注入将 Mockito 模拟插入 Spring Beans 以进行单元测试。
在实际应用程序中,组件通常依赖于访问外部系统,提供适当的测试隔离非常重要,这样我们就可以专注于测试给定单元的功能,而不必涉及每个测试的整个类层次结构。
注入模拟是引入这种隔离的一种干净的方式。
2. Maven依赖
我们需要以下 Maven 依赖项来进行单元测试和模拟对象:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.6.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.21.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 仅在“测试”配置文件处于活动状态时应用此配置。@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注解来启用“测试”配置文件并激活我们之前编写的模拟配置。因此,Spring 会自动装配UserService类的真实实例,但会模拟NameService*类。测试本身是一个相当典型的 JUnit+Mockito 测试。我们配置模拟的期望行为,然后调用我们想要测试的方法,并断言它返回我们期望的值。
也可以(尽管不推荐)避免在此类测试中使用环境配置文件。为此,我们删除了*@Profile和@ActiveProfiles注解,并将@ContextConfiguration(classes = NameServiceTestConfiguration.class)注解添加到UserServiceTest*类。