手动实例化@InjectMock带注释的字段

时间:2015-10-28 17:27:29

标签: java unit-testing junit mocking mockito

我已经浏览了一些博客,以了解Mockito注释如何工作的基础知识。

然而,我怀疑何时可以手动实例化用@InjectMocks注释的字段,即

@InjectMocks
A a = new A();

什么时候依靠MockitoAnnotations.initMocks()功能来做同样的事情:

@InjectMocks
A a;

这取决于我们用来运行测试用例的JunitTestRunner还是依赖于Mockito框架版本?

3 个答案:

答案 0 :(得分:6)

这取决于你是否正在使用(声明)跑步者。

如果你使用跑步者,你不需要自己打电话给MockitoAnnotations.initMocks() - 跑步者会为你打电话。

通常我们选择跑步者。但是当你想要使用其他跑步者时(比如春天),你可以自己打电话给.initMocks()

为了清楚起见,MockitoAnnotations.initMocks(this)会:

  • 实例化使用@InjectMocks
  • 注释的字段
  • 为使用@Mock
  • 注释的每个字段创建模拟版本
  • @Mock变量的字段中注入@InjectMocks(或调用其构造函数或使用其setter - 它取决于您使用的依赖注入类型)

Mockito runner,initMocks和规则代码示例

下面的三个代码示例应该是等效的。

使用跑步者:

此第一个代码段使用了转轮,无需调用initMocks()

@RunWith(MockitoJUnitRunner.class)
public class MyClassTest {

    @Mock private MyDependency myDependency;
    @InjectMocks private MyClass myClass;

    @Test
    public void myClass_should_get_stuff_from_dependency() {
        when(myDependency.getStuff()).thenReturn("stuff!");

        assertThat(myClass.getDependencyStuff(), is("stuff!"));
    }
}

没有转轮+手动拨打.initMocks()

另一个不使用跑步者,因此需要setUp()方法调用我们的initMocks()朋友。

// notice there is no runner
public class MyClassTest {

    @Mock private MyDependency myDependency;
    @InjectMocks private MyClass myClass;

    // but now you have to call initMocks() yourself
    @Before
    public void setUp() throws Exception {
          MockitoAnnotations.initMocks(this);
    }

    @Test
    public void myClass_should_get_stuff_from_dependency() {
        when(myDependency.getStuff()).thenReturn("stuff!");

        assertThat(myClass.getDependencyStuff(), is("stuff!"));
    }
}

没有跑步者或手动呼叫,使用@Rule

最后,正如comments (thanks @StefanBirkner)中指出的那样,自版本1.10.17起,还有可能使用名为JUnit @RuleMockitoRule

public class MyClassTest {

    @Rule
    public MockitoRule rule = MockitoJUnit.rule();

    @Mock private MyDependency myDependency;
    @InjectMocks private MyClass myClass;

    @Test
    public void myClass_should_get_stuff_from_dependency() {
        when(myDependency.getStuff()).thenReturn("stuff!");

        assertThat(myClass.getDependencyStuff(), is("stuff!"));
    }
}

答案 1 :(得分:1)

通常,是否实例化一个用@InjectMocks注释的对象的决定是代码样式的选择。在大多数情况下,由于Mockito可以处理两种情况,因此没有什么区别。

但是,我在下面概述了一些区别。

@InjectMocks使测试与对构造函数的更改脱钩。

以相同的方式使用依赖注入框架将生产代码与对构造函数的更改解耦。允许Mockito为您实例化该类的实例,从而将测试代码与对构造函数的更改解耦。这意味着将来可以对类构造函数进行任何更改,而不会引起单元测试中的编译错误。

我认为这是@InjectMocks的最大区别和最大优势。

Mockito将始终调用“最大”构造函数

注意::仅当您使用的代码未遵循最佳做法时,此区别才有意义。

当一个类中有多个构造函数时,Mocktio将调用参数最多的构造函数,即“最大”构造函数。

这只会在以下情况下产生影响

  1. “小”构造函数包含逻辑。
  2. 此逻辑是类正常运行所必需的。
  3. “最大”构造函数不会调用下一个“最小”构造函数。

这被认为是不好的做法,因为,

  1. 应尽可能避免在构造函数中放置逻辑。
  2. 如果一个类中有多个构造函数,则每个构造函数都应先调用该构造函数。

答案 2 :(得分:0)

感谢您的宝贵意见。 但是,当实例化应该通过调用MockitoAnnotations.initMocks()来处理实例化时,它仍然没有回答为什么要手动实例化使用@InjectMocks注释的字段的问题。

尝试运行测试文件时出现以下错误:

引起:org.mockito.exceptions.base.MockitoException:使用@InjectMocks注释的字段'student'为空。 请确保在 MockitoAnnotations.initMocks()之前创建实例; 正确用法示例:    class SomeTest {       @InjectMocks private Foo foo = new Foo();

  @Before public void setUp() {
     MockitoAnnotations.initMock(this);

我进一步搜索并发现如果使用较旧版本的Mockito框架则会引发错误。

http://myshittycode.com/category/testing/mockito/