Использование @Spy и @Autowired вместе
У меня есть класс обслуживания с 3 методами, класс обслуживания также использует некоторые аннотации @Autowired. Из трех методов я хочу смоделировать два метода, но использую реальный метод для третьего.
Проблема в следующем:
- Если я использую @Autowired с @Spy, вызывается реализация всех трех реальных методов.
- Если я использую только @Spy, вызов реального метода возвращается с указателем Null, поскольку инициализация объектов Autowired отсутствует.
5 ответов
Я знаю об этих двух вариантах:
- Используйте аннотацию @SpyBean из spring-boot-test как единственную аннотацию
@Autowired
@InjectMocks
private ProductController productController;
@SpyBean
private ProductService productServiceSpy;
- Использовать отражение Java для "автоматического подключения" шпионского объекта, например, ReflectionTestUtils
@Autowired
private ProductController productController;
@Autowired
private ProductService productService;
@Before
public void setUp() {
ProductService productServiceSpy = Mockito.spy(productService);
ReflectionTestUtils.setField(productController, "productService", productServiceSpy);
}
Я сам был удивлен, но это работает для нас. У нас есть много мест, таких как:
@Spy
@Autowired
private FeatureService featureService;
Я думаю, я знаю, почему вы столкнулись с этой проблемой. Дело не в инъекциях, а в when(bloMock.doSomeStuff()).thenReturn(1)
против doReturn(1).when(bloMock).doSomeStuff()
, Смотрите: http://www.stevenschwenke.de/spyingWithMockito
Очень важное различие заключается в том, что первый параметр будет вызывать метод doSomeStuff(), а второй - нет. И то и другое заставит doSomeStuff() вернуть желаемый 1.
Using @Spy
together with @Autowired
works until you want to verify interaction between that spy and a different component that spy is injected into. What I found to work for me was the following approach found at https://dzone.com/articles/how-to-mock-spring-bean-version-2
@Configuration
public class AddressServiceTestConfiguration {
@Bean
@Primary
public AddressService addressServiceSpy(AddressService addressService) {
return Mockito.spy(addressService);
}
}
This turns your autowired component into a spy object, which will be used by your service and can be verified in your tests.
У меня похожая проблема, и мы исправили ее с помощью @SpyBean и @Autowired вместе:
@SpyBean
@Autowired
ClosedInvoiceEventHandler closedInvoiceEventHandler;
ОБНОВЛЕНИЕ 20220509-203459
Для пользователя TestNg добавьте это в тестовый класс
@TestExecutionListeners(слушатели = MockitoTestExecutionListener.class)
и расширяет AbstractTransactionalTestNGSpringContextTests
тогда @SpyBean будет работать.
даются два варианта В этом ответе
Однако я столкнулся с проблемами.
- Используйте аннотацию @SpyBean из spring-boot-test в качестве единственной аннотации
Это кажется хорошей идеей, но только для пользователей junit. Я использую TestNg в своих тестах. Я не нашел способа заставить @SpyBean хорошо работать с TestNg.
- Используйте отражение Java для «автоподключения» шпионского объекта, например ReflectionTestUtils.
Кажется, что у всех bean-компонентов есть окончательные методы, потому что Spring уже проксирует их и делает методы окончательными. Таким образом, Mockito.spy может быть невозможен с автоматическим подключением bean-компонента.
Действительно, я попытался и получил исключение:
недопустимое использование сопоставителей аргументов Ожидается 0 совпадений 1 записано
Я сам не нашел причину, но я видел объяснение отсюда
Итак, остался единственный подход: /questions/3917983/ispolzovanie-spy-i-autowired-vmeste/55143842#55143842
Я не уверен, что это работает, я попробую.-- пробовал, не работает. возможно, потому что параметр метода также является прокси-сервером Spring. Методы также являются окончательными.