Как в Spring тестах заменить реализацию на мок через интерфейсы
Что проверяют
Различаете ли вы юнит-тест на Mockito и тест с поднятым контекстом Spring и знаете ли, как подменить бин в контексте. Следом часто спрашивают, почему тесты с моками стали поднимать контекст заново и тормозить.
Как отвечать
Сначала решите, нужен ли Spring вообще:
- чистый юнит-тест:
@ExtendWith(MockitoExtension.class),@Mockдля интерфейса и@InjectMocksдля тестируемого класса. При внедрении через конструктор можно просто написатьnew OrderService(paymentMock). Контекст не поднимается, тест идёт миллисекунды; - срез контекста:
@WebMvcTest(OrderController.class)или@DataJpaTestподнимают только нужный слой, а зависимости подменяются через@MockitoBean; - полный контекст:
@SpringBootTestплюс@MockitoBeanна поле типа интерфейса. Spring заменяет бин этого типа моком, и все, кто его инжектит, получают мок.
@MockitoBean и @MockitoSpyBean появились в Spring Framework 6.2, а старые @MockBean и @SpyBean из Spring Boot помечены устаревшими с Boot 3.4. В новом коде пишите новые аннотации.
Когда нужен не мок, а рабочая заглушка (in-memory хранилище, фейковый платёжный шлюз), объявите её в @TestConfiguration как @Bean с @Primary или разведите реализации профилями через @Profile("test"). Переопределять бин с тем же именем Spring Boot по умолчанию не даёт (spring.main.allow-bean-definition-overriding=false).
Роль интерфейса назовите честно: Mockito 5 по умолчанию мокает и классы, в том числе final. Интерфейс нужен не Mockito, а дизайну: тест и прод зависят от контракта, и реализацию можно подменить без наследования.
Где спотыкаются
Смешивают @SpringBootTest с @Mock и @InjectMocks. Контекст поднимается впустую, а мок в него не попадает: всё, что берётся из контекста (MockMvc, внедрённые бины), продолжает ходить в настоящий сервис.
Раскидывают разные наборы @MockitoBean по тестовым классам. Каждый уникальный набор меняет ключ кэша контекста, и Spring поднимает его заново. Общие моки выносят в базовый класс.
Добавляют mockito-core отдельной зависимостью с чужой версией. spring-boot-starter-test уже содержит JUnit Jupiter, Mockito и AssertJ совместимых версий.