java - Mockito Inject mock into Spy object

ID : 131348

viewed : 6

Tags : javaunit-testingdependency-injectionmockitojava

Top 5 Answer for java - Mockito Inject mock into Spy object

vote vote

94

I've also wandered how to inject a mock into a spy.

The following approach will not work:

@Spy @InjectMocks private MySpy spy; 

But the desired behavior can be achieved by a "hybrid" approach, when using both annotation and manual mocking. The following works perfectly:

@Mock private NeedToBeMocked needToBeMocked;  @InjectMocks private MySpy mySpy;  @InjectMocks private SubjectUnderTest sut;  @BeforeMethod public void setUp() {     mySpy = Mockito.spy(new MySpy());     MockitoAnnotations.initMocks(this); } 

(SubjectUnderTest here depends on MySpy, and MySpy in its turn depends on NeedToBeMocked).

UPD: Personally, I think that if you have to do such a magic too often, it might be a sign that there is something wrong with dependenicies between your classes and it is worth to perform a little bit of refactoring to improve your code.

vote vote

90

The (simplest) solution that worked for me.

@InjectMocks private MySpy spy = Mockito.spy(new MySpy()); 

No need for MockitoAnnotations.initMocks(this) in this case, as long as test class is annotated with @RunWith(MockitoJUnitRunner.class).

vote vote

77

Mockito cannot perform such a tricky injections as it's not an injection framework. So, you need to refactor your code to make it more testable. It's easy done by using constructor injection:

public class Engine{     private Configuration configuration;      @Inject      public Engine(Configuration configuration) {         this.configuration = configuration;     }     ........ }  public class Car{     private Engine engine;      @Inject         public Car(Engine engine) {         this.engine = engine;     } } 

In this case you have to handle the mocking and injection manually:

public class CarTestCase{      private Configuration configuration;      private Engine engine;      private Car car;      @Before     public void setUp(){         configuration = mock(Configuration.class);         engine = spy(new Engine(configuration));         car = new Car(engine);     }      @Test     public void test(){         Mockito.when(configuration.getProperties("")).return("Something");        car.drive();     }  } 
vote vote

66

I also met this issue during the unit testing with Spring boot framework, but I found one solution for using both @Spy and @InjectMocks

Previous answer from Yoory N.

@Spy @InjectMocks private MySpy spy; 

Because InjectMocks need to have instance created, so the solution works for me is at below,

@Spy @InjectMocks private MySpy spy = new MySpy(); 
vote vote

55

I think I just found the definitive answer. I tried Yoory approach but changed the order of the annotations :

@InjectMocks @Spy private MySpy spy; 

I assume that Mockito first creates the mock, and adds a spy on top of that. So there is no need to instantiate the MySpy object.

Top 3 video Explaining java - Mockito Inject mock into Spy object

Related QUESTION?