为什么Mockito @InjectMocks可能是一件可以避免的事情?

时间:2014-01-17 09:59:11

标签: java unit-testing dependency-injection mockito

为什么@InjectMocks可能会成为避免此类测试的原因。

@RunWith(MockitoJUnitRunner.class)
public class MyClassTest {

    @Mock
    private Bar bar;

    @InjectMocks
    private Foo foo; // created by Mockito

    @Test
    public void shouldCallMethod() {

        // when
        foo.myMethod();

        // then
        ...
    }
}

Foo.java

public class Foo {

    private final Bar bar;

    public Foo(Bar bar) {
        this.bar = bar;
    }
...

我在对这个答案的评论中读到了这个:https://stackoverflow.com/a/21172873/516167

关于@InjectMocks

  

标记应在其上进行注射的区域。

     
      
  • 允许速记模拟和间谍注射。
  •   
  • 尽量减少重复模拟和间谍注射。
  •   

参考:@InjectMocks JavaDoc。

2 个答案:

答案 0 :(得分:1)

我看到的唯一缺点是你必须遵守其规则。 如果您不使用@InjectMocks

,您可以获得更多控制权

从他们的文档中,我添加了一些粗体

  

Mockito将尝试仅通过构造函数注入注入模拟,   按照顺序和所描述的方式进行注入或注入   下面。如果以下任何策略失败,那么Mockito 将不会   报告失败;即你必须自己提供依赖。

     

构造函数注入; 选择最大的构造函数,然后   参数仅使用在测试中声明的模拟来解决。注意:如果   无法找到参数,然后传递null。如果是非可模拟类型   想要,然后构造函数注入不会发生。在这些情况下,   你必须自己满足依赖。

     

物业设定者注射;模拟将首先按类型解析,然后,   如果有几个相同类型的属性,则通过匹配   属性名称和模拟名称。注1:如果您有属性   相同的类型(或相同的擦除),最好命名所有@Mock   带有匹配属性的带注释字段,否则Mockito可能   感到困惑,注射不会发生。

     

注2:如果@InjectMocks实例之前没有初始化并且有一个   no-arg构造函数,然后用这个构造函数初始化它。

     

现场注入; mocks将首先按类型解析,然后,如果有的话   通过字段名称的匹配,是相同类型的几个属性   和模拟名称。注1:如果您有相同类型的字段(或   相同的擦除),最好用@命名所有@Mock注释字段   匹配字段,否则Mockito可能会混淆并注入   不会发生。

     

注2:如果@InjectMocks实例之前没有初始化并且有一个   no-arg构造函数,然后用这个构造函数初始化它。

答案 1 :(得分:1)

此外,有些人认为依赖项应该由构造函数添加,而不是由setter添加,这样在编译时保证正确的依赖。请参阅this

通过使用构造函数,您不得不限制自己使用的组件数量,以减少复杂性。 (这可能并不容易,并且在Spring中做出改变的方式很多)。

更新:在构造函数中使用自动装配的依赖项工作一段时间之后,我已经清楚地注意到测试不那么脆弱了。我仍然需要在依赖项发生变化时更改测试,但编译器会告诉我应该在哪里更改它以及更改有多大。更好的是,现在我可以区分测试的变化以适应编译时的新代码和运行时此代码添加的失败。