为了了解Mockito注释的基本工作原理,我浏览了一些博客。
然而,我面临着一个疑问,即何时可以手动实例化用@InjectMocks
注释的字段,即
@InjectMocks
A a = new A();
什么时候可以依靠MockitoAnnotations.initMocks()
功能来做同样的事情:
@InjectMocks
A a;
这取决于我们用来运行测试用例的JunitTestRunner,还是取决于Mockito框架版本?
这取决于是否使用(声明)runner。
如果你使用跑步者,你不需要自己调用MockitoAnnotations.initMocks()
——跑步者会为你调用它。
通常我们选择跑步者。不过,当您想使用其他跑步者(如Spring)时,您可以自己调用.initMocks()
。
需要明确的是,MockitoAnnotations.initMocks(this)
将:
- 实例化用
@InjectMocks
注释的字段 - 创建每个用
@Mock
注释的字段的模拟版本 - 在
@InjectMocks
变量的字段中注入@Mock
(或调用其构造函数或使用其setter——这取决于您使用的依赖注入类型)
Mockito runner、initMocks和规则代码示例
下面的三个代码示例应该是等效的。
带转轮:
第一个代码段使用了runner,因此不需要调用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()
:
另一个不使用runner,因此需要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
:
最后,正如评论中所指出的(感谢@StefanBirkner),自1.10.17版本以来,也有可能使用名为MockitoRule
:的JUnit @Rule
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!"));
}
}
通常,实例化一个用@InjectMocks
注释的对象是一种代码风格的选择。在大多数情况下不会有什么不同,因为Mockito是为处理这两种情况而设计的。
然而,我在下面概述了一些不同之处。
@InjectMocks
将测试与构造函数的更改解耦
以同样的方式,使用依赖注入框架将生产代码与构造函数的更改解耦。允许Mockito为您实例化类的实例,可以将测试代码与构造函数的更改解耦。这意味着将来对类构造函数的任何更改都可以在单元测试中不引起编译错误的情况下完成。
在我看来,这是@InjectMocks
的最大区别和最大优势。
Mockito将永远称之为";最大的";构造函数
注意:只有当您正在使用的代码没有遵循最佳实践时,这种差异才相关
当一个类中有多个构造函数时,Mocktio会调用参数最多的构造函数"最大的";构造函数。
只有当
- A";"小";构造函数包含逻辑
- 这个逻辑是类正常工作所必需的
- ";最大的";构造函数不调用下一个";最小的";构造函数
这被认为是不好的做法,因为
- 应尽可能避免在构造函数中放置逻辑
- 当一个类中有多个构造函数时,每个构造函数都应该首先调用之前的构造函数
感谢您的宝贵意见。但它仍然没有回答这样一个问题:当实例化应该由对MockitoAnnotations.initMocks()
的调用来处理时,为什么要手动实例化用@InjectMocks
注释的字段。
我在尝试运行测试文件时遇到以下错误:
由:org.mockito.exceptions.base.MockitoException引起:用@InjectMocks注释的字段"student"为null。请确保在MockitoAnnotations.initMocks()之前创建了实例;正确用法示例:
class SomeTest { @InjectMocks private Foo foo = new Foo(); @Before public void setUp() { MockitoAnnotations.initMock(this);
我进一步搜索,发现如果使用的是旧版本的Mockito框架,就会抛出错误。
http://myshittycode.com/category/testing/mockito/