Java Mockito@InjectMocks不';不适用于相同类型的字段

Java Mockito@InjectMocks不';不适用于相同类型的字段,java,unit-testing,mockito,inject,Java,Unit Testing,Mockito,Inject,我非常惊讶地发现,下面的简单代码示例并不适用于所有大于1.8.5的Mockito版本 @RunWith(MockitoJUnitRunner.class) public class MockitoTest { @Mock(name = "b2") private B b2; @InjectMocks private A a; @Test public void testInjection() throws Exception {

我非常惊讶地发现,下面的简单代码示例并不适用于所有大于1.8.5的Mockito版本

@RunWith(MockitoJUnitRunner.class)
public class MockitoTest {

    @Mock(name = "b2")
    private B b2;

    @InjectMocks
    private A a;

    @Test
    public void testInjection() throws Exception {
        assertNotNull(a.b2); //fails
        assertNull(a.b1); //also fails, because unexpectedly b2 mock gets injected here
    }

    static class A{
        private B b1;
        private B b2;
    }

    interface B{}
}
在javadocs()中有一个引号:

注1:如果您有相同类型(或相同擦除)的字段,则 最好使用匹配字段命名所有@Mock注释字段, 否则Mockito可能会困惑,注射不会发生

这是否意味着如果我有几个相同类型的字段,我不能只模拟其中一个字段,而是应该为所有相同类型的字段定义
@mock
? 这是已知的限制,有什么原因它还没有被修复?
通过字段名匹配
@Mock
应该很简单,不是吗?

Mockito似乎使用了中描述的算法

如果我理解正确,它将首先按类型排序(在本例中仅为1b),然后按名称排序(此处无更改)。它最终将使用注入,这似乎是搜索第一个字段并注入它

由于您只定义了1个B,并且在模拟中有2个B字段,因此它将看到第一个实例与字段的匹配并停止。这是因为中的
mock.size()==1
. 因此,它将停止过滤并直接注入。如果创建同一类型的多个模拟,它们将按名称排序并相应地注入

当我创建了一个特定类型的多个mock(但少于字段的数量)时,我能够让它工作

@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 {
    }
}
这将正确地将b2插入a.b2,将b3插入a.b3,而不是a.b1和a.b2(a中定义的前两个字段)


您可以随时将GitHub问题保留在他们的存储库中,并对注入过滤算法进行增强或更改,以供查看。

如果存在多个相同类型的模拟,则在mockito中将此作为解决方法进行记录。它不会根据提供的名称解析实现(即
@Mock(name=“b2”)
)。它用来解析实现的算法是通过注入依赖项的字段名来解析的。因此,上面的代码将正确解析(
b2
=>
@Mock private B b2
b3
=>
@Mock private B b3


另一个解决方法是使用构造函数注入,这是注入依赖项的推荐方法。

实际上,对于这种合法的情况,注入肯定会变得更聪明一些,但安全性是强制性的。注射是自动发生的,所以Mockito应该表现得很不情愿,以避免做坏事。另外,如果注入很复杂,那么您的对象要么太复杂,要么必须遵循另一种创建模式(例如Joshua Bloch builder),这是一个已知的问题,并且当在测试的系统中存在相同类型的模拟接口时,您的上述代码是一种解决方法。