Home > OS >  @InjectMocks is not injecting the the list dependency, which is a @Spy
@InjectMocks is not injecting the the list dependency, which is a @Spy

Time:07-14

Servcice.java (class to test)

class Service {
    @Autowired
    private List<Metric> dependency1;
    @Autowired
    private Executor dependency2;

}

Metric.java : interface

  interface Metric{
        public void fetchMetric();
    }

class Metric1 implements Metric{
        public void fetchMetric() {}
    }

class Metric2 implements Metric{
        public void fetchMetric() {}
    }

ServiceTest.java : (test class)

  @ExtendWith(MockitoExtension.class)
    class ServiceTest {
        @Spy
        private List<Metric> dependency1;
        @Mock
        private Executor dependency2;
        
        @InjectMocks // class under test // this has above two as their dependencies.
        Service service;
    
        @Mock
        private Metric1 metric1;
        @Mock
        private Metric2 metric2;
    
        @BeforeEach
        void setUp() {
            // intializing the spy object list with mocks.
            this.dependency1 = Arrays.asList(metric1,
                    metric2
                   );
        }
    
        @Test
        void someTest() {
            // here in debug mode I can see that `dependency1` as a **spy**  and 'dependency1' present in the 'Service' are different, though they should be same.
        }
    }

Why @InjectMock is not able to Inject a @Spy List dependencies in the Service class object? Am I missing something here.

dependency1 as a spy and dependency1 present as a part of the Service are shown as two different objects on the de-bugger and making the test cases fail. I thought they should be the same.

Should we not initialise the Spies in @BeforeEach method ?

CodePudding user response:

The problem is you use @ExtendWith(MockitoExtension.class) to tell mockito to instantiate your @Mocks @Spy and @InjectMocks. So after Mockito does this you change the field ServiceTest.dependency1 to be a list.

But since Mockito instantiated your CUT with the annotated dependencies, it is not updated when you change the ServiceTest.dependency1.

I would recommend to change Service to have a constructor so you can use the recommended constructor Injection. That way you can make your test like this:

@ExtendWith(MockitoExtension.class)
class ServiceTest {
    
    @Mock
    private Executor dependency2;
    
    Service service;

    @Mock
    private Metric1 metric1;
    @Mock
    private Metric2 metric2;

    @BeforeEach
    void setUp() {
        // intializing the spy object list with mocks.
        service = new Service(Arrays.asList(metric1,metric2), dependency2);
    }
}

CodePudding user response:

One way to handle it:

Remove @Spy and use @Mock on dependency1.

And you will need to handle the List w.r.t. the testcase like:

Mockito.doReturn(metric1).when(dependency1).get(ArgumentMatchers.anyString());

  • Related