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 .