Mockito @InjectMocks doesn't work for fields with same type

前端 未结 2 1461
陌清茗
陌清茗 2021-02-07 06:43

I was very surprised to find out that following simple code example doesn\'t work for all Mockito versions > 1.8.5

@RunWith(MockitoJUnitRunner.class)
public clas         


        
相关标签:
2条回答
  • 2021-02-07 07:39

    It appears Mockito uses an algorithm described in their JavaDoc

    If I understand correctly, it will first sort on type (in this case only 1 B) and then sort on name (no changes here). It will finally inject using the OngoingInjector interface implementation, which appears to search for the first field and inject it.

    Since you only have 1 B defined and there are 2 fields of B in the Mock, it will see the match of the first instance to the field and stop. This is because mocks.size() == 1 in NameBasedCandidateFilter . Therefore it will stop filtering and inject it directly. If you create multiple mocks of the same type, they will get sorted on Name and injected accordingly.

    I was able to get it work when I created multiple mocks (but less than the number of fields) of a specific type.

    @RunWith(MockitoJUnitRunner.class)
    public class MockitoTest {
    
        @Mock(name = "b2")
        private B b2;
    
        @Mock(name = "b3")
        private B b3;
    
        @InjectMocks
        private A a;
    
        @Test
        public void testInjection() {
            System.out.println(this.a);
        }
    
        static class A {
    
            private B b1;
    
            private B b2;
    
            private B b3;
        }
    
        interface B {
        }
    }
    

    This will correctly inject b2 into a.b2 and b3 into a.b3 instead of a.b1 and a.b2 (the first 2 fields that are defined in A).

    You can always leave a GitHub issue on their repository with an enhancement or change on the injection filtering algorithm in order to be looked at.

    0 讨论(0)
  • 2021-02-07 07:40

    This is documented in mockito as work around, if multiple mocks exists of the same type. It does not resolve the implementation based on the name provided (ie @Mock(name = "b2")). The algorithm it uses to resolved the implementation is by field name of the injected dependency. So your code above will resolve correctly (b2 => @Mock private B b2 and b3 => @Mock private B b3).

    The other workaround is to use constructor injection which is the recommended way of injecting dependencies.

    0 讨论(0)
提交回复
热议问题