1. Обзор
В этой статье мы покажем, как использовать инъекцию зависимостей для вставки Mockito mocks в Spring Beans для модульного тестирования.
В реальных приложениях, где компоненты часто зависят от доступа к внешним системам, важно обеспечить надлежащую изоляцию тестов, чтобы мы могли сосредоточиться на тестировании функциональности данного модуля без необходимости задействовать всю иерархию классов для каждого теста.
Инъекция макета – это чистый способ ввести такую изоляцию.
2. Зависимости Maven
Нам нужны следующие зависимости Maven для модульных тестов и макетных объектов:
org.springframework.boot spring-boot-starter 2.4.0 org.springframework.boot spring-boot-starter-test 2.4.0 test org.mockito mockito-core 2.21.0
Мы решили использовать Spring Boot для этого примера, но классическая пружина также будет отлично работать.
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);
}
}В этом учебнике данные классы возвращают одно имя независимо от предоставленного идентификатора. Это делается для того, чтобы мы не отвлекались на тестирование какой-либо сложной логики.
Нам также понадобится стандартный основной класс Spring Boot для сканирования компонентов и инициализации приложения:
@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 предназначена для того, чтобы убедиться, что этот экземпляр используется вместо реального для автозапуска. Метод сам создает и возвращает макет нашего класса Name Service .
Теперь мы можем написать модульный тест:
@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.class) аннотация к классу UserServiceTest .
4. Заключение
В этом кратком уроке мы показали, как легко вводить насмешки Mockito в весенние бобы.
Как обычно, все примеры кода доступны на GitHub .