Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using @Spy and @Autowired together

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:

  1. If I am using @Autowired with @Spy, all three real method implementation is being called.
  2. If I am using @Spy only, call to real method is return with Null pointer as there is no initialisation of Autowired objects.
like image 400
Shashi K Kalia Avatar asked Jun 09 '17 10:06

Shashi K Kalia


People also ask

Can we use Autowired with @component?

So the answer is: No, @Autowired does not necessarily mean you must also use @Component . It may be registered with applicationContext. xml or @Configuration+@Bean . @Autowired on the construct makes no sense in the above example...

Is @autowired used for dependency injection?

Spring @Autowired annotation is used for automatic dependency injection. Spring framework is built on dependency injection and we inject the class dependencies through spring bean configuration file.

Why should not we use Autowiring?

There are several reasons @Autowired might not work. When a new instance is created not by Spring but by for example manually calling a constructor, the instance of the class will not be registered in the Spring context and thus not available for dependency injection.

What @autowired annotation uses for bean injection?

The @Autowired annotation provides more fine-grained control over where and how autowiring should be accomplished. The @Autowired annotation can be used to autowire bean on the setter method just like @Required annotation, constructor, a property or methods with arbitrary names and/or multiple arguments.


2 Answers

I know about these two options:

  1. Use @SpyBean annotation from spring-boot-test as the only annotation
@Autowired
@InjectMocks
private ProductController productController;

@SpyBean
private ProductService productServiceSpy;
  1. Use Java reflection to "autowire" the spy object, e.g. ReflectionTestUtils
@Autowired
private ProductController productController;

@Autowired
private ProductService productService;

@Before
public void setUp() {
    ProductService productServiceSpy = Mockito.spy(productService);
    ReflectionTestUtils.setField(productController, "productService", productServiceSpy);
}
like image 166
PROrock Avatar answered Oct 26 '22 00:10

PROrock


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.

like image 16
yuranos Avatar answered Oct 25 '22 23:10

yuranos