spring Mockito @InjectMocks 如何工作?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15228777/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How does Mockito @InjectMocks work?
提问by DYezek
Here's my question:
这是我的问题:
I have several web services classes to test that all inherit their methods from a generic service. Rather than write a unit test for each, I figure I can break the test suite down by functional areas (i.e. three groups of test methods, each relying on a different underlying DAO method call).
我有几个 Web 服务类来测试它们是否都从通用服务继承了它们的方法。与其为每一个都编写一个单元测试,我想我可以按功能区域分解测试套件(即三组测试方法,每组都依赖于不同的底层 DAO 方法调用)。
What I propose to do is:
我建议做的是:
@Mock StateDAO mockedStateDao;
@Mock CountyDAO mockedCountyDao;
@Mock VisitorDAO mockedVisitorDao;
then call:
然后调用:
@InjectMocks CountyServiceImpl<County> countyService = new CountyServiceImpl<County>();
@InjectMocks StateServiceImpl<State> stateService = new StateServiceImpl<State>();
@InjectMocks VisitorServiceImpl<Visitor> visitorService = new VisitorServiceImpl<Visitor>();
How can I be sure that each mockedDAO will be injected into the correct service? Would it be easier to autowire all three (rather than use @InjectMocks)?
我如何确保每个 mockedDAO 都会被注入到正确的服务中?自动装配所有三个(而不是使用@InjectMocks)会更容易吗?
I'm using Spring, Hibernate, and Mockito...
我正在使用 Spring、Hibernate 和 Mockito...
回答by Brice
Well nicholas answer is almost correct, but instead of guessing just look at the javadoc of InjectMocks, it contains more details ;)
好吧,尼古拉斯的回答几乎是正确的,但与其猜测,不如看看InjectMocks的 javadoc ,它包含更多细节;)
To me it's weird to have so many Service in a single test, it doesn't feel right, as a unit test or as an integration test. In unit test it's wrong because well you have way too much collaborators, it doesn't look like object oriented (or SOLID). In integration tests, it's weird because the code you test the integration with the DB not mock it.
对我来说,在一个测试中拥有这么多服务很奇怪,作为单元测试或集成测试感觉不对。在单元测试中这是错误的,因为你有太多的合作者,它看起来不像面向对象(或 SOLID)。在集成测试中,这很奇怪,因为您测试与数据库集成的代码并没有模拟它。
For a rapid reference in 1.9.5 you have :
对于 1.9.5 中的快速参考,您有:
Mark a field on which injection should be performed.
Allows shorthand mock and spy injection. Minimizes repetitive mock and spy injection. Mockito will try to inject mocks only either by constructor injection, setter injection, or property injection in order and as described below. If any of the following strategy fail, then Mockito won't report failure; i.e. you will have to provide dependencies yourself.
Constructor injection;the biggest constructor is chosen, then arguments are resolved with mocks declared in the test only.
Note:If arguments can not be found, then null is passed. If non-mockable types are wanted, then constructor injection won't happen. In these cases, you will have to satisfy dependencies yourself.
Property setter injection;mocks will first be resolved by type, then, if there is several property of the same type, by the match of the property name and the mock name.
Note 1:If you have properties with the same type (or same erasure), it's better to name all @Mock annotated fields with the matching properties, otherwise Mockito might get confused and injection won't happen.
Note 2:If @InjectMocks instance wasn't initialized before and have a no-arg constructor, then it will be initialized with this constructor.
Field injection;mocks will first be resolved by type, then, if there is several property of the same type, by the match of the field name and the mock name.
Note 1:If you have fields with the same type (or same erasure), it's better to name all @Mock annotated fields with the matching fields, otherwise Mockito might get confused and injection won't happen.
Note 2:If @InjectMocks instance wasn't initialized before and have a no-arg constructor, then it will be initialized with this constructor.
标记应执行注射的字段。
允许速记模拟和间谍注入。最大限度地减少重复的模拟和间谍注入。Mockito 将尝试仅通过构造函数注入、setter 注入或属性注入依次注入模拟,如下所述。如果以下任一策略失败,则 Mockito 不会报告失败;即您必须自己提供依赖项。
构造函数注入;选择最大的构造函数,然后使用仅在测试中声明的模拟来解析参数。
注意:如果找不到参数,则传递 null。如果需要不可模拟的类型,则不会发生构造函数注入。在这些情况下,您必须自己满足依赖项。
属性设置器注入;mocks 将首先按类型解析,然后,如果有多个相同类型的属性,则通过属性名称和模拟名称的匹配。
注意1:如果你有相同类型(或相同擦除)的属性,最好用匹配的属性命名所有@Mock注解的字段,否则Mockito可能会混淆并且不会发生注入。
注2:如果@InjectMocks 实例之前没有初始化并且有一个无参数构造函数,那么它将用这个构造函数初始化。
现场注入;mocks 将首先按类型解析,然后,如果有多个相同类型的属性,则通过字段名称和模拟名称的匹配。
注意1:如果你有相同类型(或相同擦除)的字段,最好用匹配的字段命名所有@Mock注释的字段,否则Mockito可能会混淆并且不会发生注入。
注2:如果@InjectMocks 实例之前没有初始化并且有一个无参数构造函数,那么它将用这个构造函数初始化。
回答by giesemic
If you have multiple Services and would like to replace the DAOs with Mock-Objects in a Spring-based environment, I would recommend to use Springockito: https://bitbucket.org/kubek2k/springockito/wiki/Home
如果您有多个服务并且想在基于 Spring 的环境中用 Mock-Objects 替换 DAO,我建议使用 Springockito:https://bitbucket.org/kubek2k/springockito/wiki/Home
which is also mentioned here: Injecting Mockito mocks into a Spring bean
这里也提到了: Injecting Mockito mocks into a Spring bean
Your Testclass then might look like this:
您的 Testclass 可能如下所示:
@RunWith (SpringJUnit4ClassRunner.class)
@ContextConfiguration (loader = SpringockitoContextLoader.class, locations = {"classpath:/org/example/package/applicationContext.xml"})
public class NameOfClassTest {
@Autowired
@ReplaceWithMock
StateDAO mockedStateDao;
@Autowired
@ReplaceWithMock
CountyDAO mockedCountyDao;
@Autowired
@ReplaceWithMock
VisitorDAO mockedVisitorDao;
In your @Test or @Before Methode you can setup your mocks the standard Mockito way:
在你的 @Test 或 @Before Methode 中,你可以用标准的 Mockito 方式设置你的模拟:
Mockito.doReturn(null).when(mockedCountyDao).selectFromDB();
回答by nicholas.hauschild
Well, the static method MockitoAnnotations.initMocks(Object)is used to bootstrap the whole process.
那么,静态方法MockitoAnnotations.initMocks(Object)用于引导整个过程。
I don't know for sure how it works, as I haven't browsed the source code, but I would implement it something like this:
我不确定它是如何工作的,因为我没有浏览过源代码,但我会像这样实现它:
- Scan the passed
Object's class for member variables with the@Mockannotation. - For each one, create a mock of that class, and set it to that member.
- Scan the passed
Object's class for member variables with the@InjectMocksannotation. - Scan the class of each found member for members it has that can be injected with one of the mock objects created in (2) (that is, where the field is a parent class/interface, or the same class, as the mock objects declared class) and set it to that member.
Object使用@Mock注释扫描传递的类中的成员变量。- 对于每个类,创建该类的模拟,并将其设置为该成员。
Object使用@InjectMocks注释扫描传递的类中的成员变量。- 扫描每个找到的成员的类,以查找可以注入 (2) 中创建的模拟对象之一的成员(即,该字段是父类/接口,或与声明的模拟对象相同的类)类)并将其设置为该成员。
回答by DYezek
Nevermind, looked online- the InjectMocks annotation treats anything with the @Mock annotation as a field and is static-scoped (class wide), so I really couldn't guarentee that the mocks would go to the correct service. this was somewhat a thought experiment for trying to unit test at feature level rather than class level. Guess I'll just autowire this stuff with Spring...
没关系,在线查看 - InjectMocks 注释将带有 @Mock 注释的任何内容视为一个字段,并且是静态范围的(类宽),所以我真的无法保证模拟会转到正确的服务。这在某种程度上是尝试在功能级别而不是类级别进行单元测试的思想实验。猜猜我会用 Spring 自动装配这些东西......

