Mockito @InjectMocks不适用于具有相同类型

时间:2015-04-29 18:52:37

标签: java unit-testing mockito inject

我很惊讶地发现以下简单的代码示例并不适用于所有Mockito版本> 1.8.5

@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(http://docs.mockito.googlecode.com/hg/latest/org/mockito/InjectMocks.html)中有一个引用:

  

注1:如果你有相同类型(或相同的擦除)的字段,那就是   最好用匹配的字段命名所有@Mock带注释的字段,   否则Mockito可能会感到困惑,注射也不会发生。

这是否意味着如果我有几个相同类型的字段,我不能只模拟其中一个,而应该为同一类型的所有字段定义@Mock? 是否已知限制,是否有任何原因尚未解决? 按字段名称匹配@Mock应该是直截了当的,不是吗?

2 个答案:

答案 0 :(得分:20)

看来Mockito使用their JavaDoc

中描述的算法

如果我理解正确,它将首先对类型进行排序(在这种情况下只有1 B)然后按名称排序(此处不做更改)。它最终将使用the OngoingInjector interface implementation注入,它似乎搜索第一个字段并将其注入。

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

当我创建特定类型的多个模拟(但少于字段数)时,我能够使它工作。

@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中定义的前2个字段)。

您可以随时在其存储库中留下GitHub问题,并对注入过滤算法进行增强或更改,以便进行查看。

答案 1 :(得分:0)

如果存在多个相同类型的模拟,则会在mockito中记录这种情况。它不会根据提供的名称解析实现(即@Mock(name = "b2"))。它用于解析实现的算法是注入依赖项的字段名称。因此,上面的代码将正确解析(b2 => @Mock private B b2b3 => @Mock private B b3)。

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