#spring #spring-boot #junit #mockito
#весна #spring-boot #junit #mockito
Вопрос:
Я использую JUnit5 для тестирования приложения Spring Boot. Я хочу протестировать @Service
объект, который использует @Autowired
поля. Я хотел бы издеваться над другим @Service
объектом, который косвенно используется моим тестовым объектом. Конкретно, у меня есть следующая (сильно упрощенная) настройка:
Тестируемый объект:
@Service
public class MainService {
private @Autowired SubService subService;
public String test() {
return subService.test();
}
}
SubService
:
@Service
public class SubService {
private @Autowired StringService stringService;
public String test() {
return stringService.test();
}
}
StringService
:
@Service
public class StringService {
public String test() {
return "Real service";
}
}
Используемый тестовый класс:
@SpringBootTest
public class MainServiceTest {
private @Autowired MainService mainService;
private @MockBean StringService stringService;
@BeforeEach
public void mock() {
Mockito.when(stringService.test()).thenReturn("Mocked service");
}
@Test
public void test() {
assertEquals("Mocked service", mainService.test());
}
}
Вышеуказанное работает, если я запускаю тестовый класс как @SpringBootTest
, но это загружает все приложение и работает очень медленно. Я также хочу избежать, @WebMvcTest
поскольку мне не нужен веб-сервер или @DataJpaTest
поскольку мне не нужна сохраняемость. Я не хочу издеваться SubService
, поскольку он содержит функциональность, которую я хочу протестировать вместе с MainService
.
Я попробовал следующее:
@ExtendWith(SpringExtension.class)
=> бросаетNoSuchBeanDefinitionException
, похоже, что автоматическое подключение в этом случае не работает@ExtendWith(MockitoExtension.class)
и использование@InjectMocks
и@Mock
вместо аннотаций Spring => посколькуStringService
это не прямое полеMainService
тестируемого, это не работает.
Есть ли способ использовать систему внедрения зависимостей Spring без загрузки веб-сервера или уровня сохранения или, альтернативно, не использовать тесты Spring, но разрешить внедрение «вложенных» зависимостей?
Комментарии:
1. Какой класс вы пытаетесь протестировать? Почему вы не можете имитировать SubService при тестировании MainService и писать модульные тесты для SubService отдельно?
2. @msfoster Я тестирую MainService. Технически я могу имитировать SubService, но я предпочитаю этого не делать, поскольку это не имеет большого смысла в базовой реализации (макет будет просто копией кода в SubService).
3. Заглушки просты, подходят для тестового примера. Зачем вам копировать реализацию?
4. Если вы приведете пример метода, который вы хотели бы протестировать, вам будет проще помочь 🙂
5. Я вижу, что вы уже используете зависимость Mockito для своего теста, и вы хотите избежать
SpringBootTest
, почему бы тогда не использовать @Mock и @InjectMock Mockito для простого модульного тестирования того, что вам нужно?
Ответ №1:
Вы можете использовать профилирование (т. Е. Spring @Profile
), чтобы избежать загрузки всего приложения. Это будет выглядеть примерно так, как показано ниже:
@Profile("test")
@Configuration
public class TestConfiguration {
@Bean
public MainService mainService() {
return new MainService();
}
@Bean
public SubService subService() {
return new SubService();
}
// mock the StringService
@Bean
public StringService stringService() {
return Mockito.mock(StringService.class);
}
}
затем используйте этот профиль с помощью `@SpringBootTest(классы = TestConfiguration.class ), это будет выглядеть примерно так, как показано ниже:
@ActiveProfiles("test")
@SpringBootTest(classes = TestConfiguration.class)
class MainServiceTest {
@Autowired
private MainService mainService;
@Test
public void test() {
// configure behavior using apis like when(), basically however you
// want your mock to behave
}
}
При этом будут загружены только компоненты, определенные в классе TestConfiguration
.
ПРИМЕЧАНИЕ: Поскольку ваш вопрос больше касается того, как избежать загрузки всего приложения, я ответил, сосредоточившись на этом. Приведенный выше подход позволит выполнить работу, но я бы предпочел подключение конструктора любому другому способу внедрения зависимостей в любой день, его проще поддерживать и тестировать (например, случаи, когда вы хотите издеваться).