#spring-boot #kotlin #mockito
#пружинный ботинок #котлин #мокито
Вопрос:
Я пытаюсь протестировать такой класс, как
@TestInstance(TestInstance.Lifecycle.PER_CLASS) @SpringBootTest(classes = [TestConfig::class]) @ExtendWith(MockitoExtension::class) class TotalCalculatorTests { @Mock lateinit var jdbcRepo: JDBCRepo @Mock lateinit var userCache : LoadingCachelt;ApproverLevel, Listlt;Approvergt;gt; @InjectMocks lateinit var calculator: TotalCalculator @Test fun totalOrder() { // val calculator = TotalCalculator(userCache,jdbcRepo) calculator.total(ItemA(),ItemB()) verify(jdbcRepo).getTotal() } }
Я получаю ошибку Actually, there were zero interactions with this mock.
, но если я раскомментирую // val calculator = TotalCalculator(userCache,jdbcRepo)
, это сработает. Я предполагал, что mockito будет использовать насмешки из тестового класса, но это, похоже, не так. Как я могу получить экземпляр JDBCRepo, используемый @InjectMocks?
Ответ №1:
Похоже, вы хотели бы запустить полноценный тест весенней загрузки со всеми компонентами, но в контексте приложения вы хотели бы «поиздеваться» над некоторыми реальными компонентами и предоставить свою собственную (макет-у) реализацию.
Если это так, то использование @Mock
здесь неверно. @Mock
не имеет никакого отношения к весне, это чисто шутливая вещь. Он действительно может создать макет для вас, но он не «заменит» реальную реализацию этой макетной реализацией в контексте приложения spring boot.
Для этой цели @MockBean
вместо этого используйте аннотацию. Это что-то из весенней «вселенной», которая действительно создает макет, управляемый макетом, под капотом, но заменяет обычный компонент в контексте приложения (или даже просто добавляет эту макет-реализацию в контекст приложения, если реальный компонент даже не существует).
Еще одна вещь, которую следует учитывать, — как вы получаете TotalCalculator
боб (хотя вы прямо не задаете этого в вопросе).
Сам TotalCalculator
по себе, вероятно, является пружинным компонентом, который создает для вас spring boot, поэтому, если вы хотите запустить «полноценный» тест, вам следует взять экземпляр этого компонента из контекста приложения, а не создавать экземпляр самостоятельно. Используйте аннотации @Autowired
для этой цели:
@TestInstance(TestInstance.Lifecycle.PER_CLASS) @SpringBootTest(classes = [TestConfig::class]) @ExtendWith(MockitoExtension::class) // you don't need this class TotalCalculatorTests { @MockBean lateinit var jdbcRepo: JDBCRepo @MockBean lateinit var userCache : LoadingCachelt;ApproverLevel, Listlt;Approvergt;gt; @Autowired // injected by the spring test infrastructure lateinit var calculator: TotalCalculator @Test fun totalOrder() { // val calculator = TotalCalculator(userCache,jdbcRepo) calculator.total(ItemA(),ItemB()) verify(jdbcRepo).getTotal() } }
Теперь все это правильно, если ваша цель действительно запустить полный микросервис spring boot и провести «интеграционное» тестирование
Если в качестве альтернативы вы просто хотите проверить код своего калькулятора, это может быть излишним, вы можете в конечном итоге использовать mockito и обычное модульное тестирование. В этом случае, однако, вам не нужно даже запускать spring (читай «создать контекст приложения») во время теста, и, конечно, нет необходимости использовать @SpringBootTest
/ @MockBean
/ @Autowired
.
Так что это в значительной степени зависит от того, какой тест здесь действительно требуется
Комментарии:
1. да, я хочу интеграционный тест, большое вам спасибо за удивительный ответ!!!