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

为什么@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。

我看到的唯一缺点是你必须遵守它的规则。 如果不使用@InjectMocks@InjectMocks更多控制@InjectMocks

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

Mockito将尝试仅通过构造函数注入,setter注入或属性注入按顺序注入模拟,如下所述。 如果以下任何一种策略失败,那么Mockito 将不会报告失败 ; 即你必须自己提供依赖。

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

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

注意2:如果之前没有初始化@InjectMocks实例并且有一个no-arg构造函数,那么它将使用此构造函数进行初始化。

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

注意2:如果之前没有初始化@InjectMocks实例并且有一个no-arg构造函数,那么它将使用此构造函数进行初始化。

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

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

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