Как заинжектить моки в класс с помощью Mockito?
Что проверяют
Знаете ли вы разницу между ручной передачей мока и @InjectMocks и по каким правилам Mockito выбирает способ внедрения. Следом часто спрашивают, почему после @InjectMocks зависимость внутри класса оказалась null и чем такой тест отличается от теста с @MockitoBean в Spring.
Как отвечать
Способа три, по порядку предпочтения:
- конструктор руками:
var repo = mock(Repository.class); var service = new Service(repo);. Никакой магии, зависимости класса видны сразу; - аннотации:
@ExtendWith(MockitoExtension.class)изmockito-junit-jupiter, поля с@Mockи тестируемое поле с@InjectMocks. В JUnit 4 то же даётMockitoJUnitRunner, без раннера вызываютMockitoAnnotations.openMocks(this), старыйinitMocksустарел; - Spring-контекст:
@MockitoBeanподменяет бин в контексте@SpringBootTestили@WebMvcTest. Прежний@MockBeanпомечен устаревшим с Spring Boot 3.4.
Как работает @InjectMocks: сначала конструктор с наибольшим числом параметров, куда подставляются моки по типу, а недостающие аргументы передаются как null. Если конструктора с параметрами нет, Mockito идёт через сеттеры, затем через поля: по типу, а при нескольких кандидатах одного типа по имени. Главное: при неудачном внедрении ошибки не будет, поле просто останется null.
Отсюда практичный вывод: делайте зависимости final и принимайте их через конструктор. Тогда и @InjectMocks, и ручная сборка работают предсказуемо.
В Mockito 5 по умолчанию inline mock maker, поэтому final-классы мокаются без отдельного артефакта, а MockitoExtension работает в строгом режиме и падает на лишних заглушках с UnnecessaryStubbingException.
Где спотыкаются
Забывают @ExtendWith(MockitoExtension.class) или раннер. Аннотации никто не обрабатывает, все @Mock остаются null, и тест падает с NPE.
Ждут от @InjectMocks ошибки при неудачном внедрении. Её нет: при двух зависимостях одного типа и несовпадении имён поле молча остаётся пустым, и NPE вылетает далеко от причины.
Мокают всё подряд, включая DTO и сам тестируемый класс. Мокают внешние зависимости: репозитории, HTTP-клиенты, Clock, а объекты-значения создают настоящими.