Reputation: 733
I have a Service Class with 3 methods, Service class is also using some @Autowired annotations. Out of 3 methods, I want to mock two methods but use real method for 3rd one.
Problem is:
Upvotes: 57
Views: 57275
Reputation: 157
I have a similar problem and we fixed using @SpyBean and @Autowired together:
@SpyBean
@Autowired
ClosedInvoiceEventHandler closedInvoiceEventHandler;
Upvotes: 6
Reputation: 31
UPDATE 20220509-203459
For TestNg User, Add this to the test class
@TestExecutionListeners(listeners = MockitoTestExecutionListener.class)
and extends AbstractTransactionalTestNGSpringContextTests
then @SpyBean will work.
Two choices are given in this Answer
Howerver, I met problems.
This seems a good idea but only for junit users. I am using TestNg in my tests. I have not found a way to make @SpyBean work well with TestNg.
The beans autowired seem all have final methods, because spring have already proxy them and make methods final. So Mockito.spy a autowired bean maybe impossible.
Indeed, i tried and got a exception:
invalid use of argument matchers 0 matchers expected 1 recorded
I didnot find reason myself but i saw explanation from here
So, the only approach left is https://stackoverflow.com/a/55148514/12133207
I am not sure if it does work, I will try. -- tried,not work. maybe because the method parameter is also spring proxied. The methods are alse final.
Upvotes: 0
Reputation: 61
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.
Upvotes: 6
Reputation: 9685
I was surprised myself but it does work for us. We have plenty places like:
@Spy
@Autowired
private FeatureService featureService;
I think I know why you are facing this problem. It's not about injection, it's about when(bloMock.doSomeStuff()).thenReturn(1)
vs doReturn(1).when(bloMock).doSomeStuff()
.
See: http://www.stevenschwenke.de/spyingWithMockito
The very important difference is that the first option will actually call the doSomeStuff()- method while the second will not. Both will cause doSomeStuff() to return the desired 1.
Upvotes: 21
Reputation: 1200
I know about these two options:
@Autowired
@InjectMocks
private ProductController productController;
@SpyBean
private ProductService productServiceSpy;
@Autowired
private ProductController productController;
@Autowired
private ProductService productService;
@Before
public void setUp() {
ProductService productServiceSpy = Mockito.spy(productService);
ReflectionTestUtils.setField(productController, "productService", productServiceSpy);
}
Upvotes: 108