我的问题是:
我有几个web服务类来测试它们从一个通用服务继承的方法。与其为每个测试都编写单元测试,不如将测试套件按功能区域分解(例如,三组测试方法,每组依赖于不同的底层DAO方法调用)。
我的建议是:
@Mock StateDAO mockedStateDao;
@Mock CountyDAO mockedCountyDao;
@Mock VisitorDAO mockedVisitorDao;
然后调用:
@InjectMocks CountyServiceImpl<County> countyService = new CountyServiceImpl<County>();
@InjectMocks StateServiceImpl<State> stateService = new StateServiceImpl<State>();
@InjectMocks VisitorServiceImpl<Visitor> visitorService = new VisitorServiceImpl<Visitor>();
如何确保每个mockedDAO将被注入到正确的服务中?自动装配这三个会不会更容易(而不是使用@InjectMocks)?
我正在使用Spring, Hibernate和Mockito…
nicholas的回答几乎是正确的,但是不要猜测,只要看看InjectMocks的javadoc,它包含更多的细节;)
对我来说,在一个测试中有这么多的服务是很奇怪的,它感觉不合适,作为一个单元测试或集成测试。在单元测试中,这是错误的,因为你有太多的合作者,它看起来不像面向对象(或SOLID)。在集成测试中,这很奇怪,因为测试与DB集成的代码不是模拟它。
对于1.9.5中的快速参考,您有:
标记一个应该执行注入的字段。
允许速记模拟和间谍注入。最小化重复的模拟和间谍注入。Mockito将尝试只通过构造函数注入、setter注入或属性注入注入mock,顺序如下所述。如果以下任何策略失败,那么Mockito将不会报告失败;也就是说,你必须自己提供依赖项。
构造函数注入;选择最大的构造函数,然后使用仅在测试中声明的mock来解析参数。
注意:如果找不到参数,则传递null。如果需要不可模拟的类型,则不会发生构造函数注入。在这些情况下,您将不得不自己满足依赖项。
属性setter注入;模拟将首先按类型解析,然后,如果有几个相同类型的属性,则通过属性名称和模拟名称的匹配来解析。
注1:如果您有相同类型的属性(或相同的擦除),最好使用匹配的属性命名所有带@Mock注释的字段,否则Mockito可能会混淆,并且不会发生注入。
注2:如果@InjectMocks实例之前没有初始化,并且有一个无参数的构造函数,那么它将被这个构造函数初始化。
字段注入;模拟将首先按类型解析,然后,如果有几个相同类型的属性,则通过字段名称和模拟名称的匹配来解析。
注1:如果您有相同类型的字段(或相同的擦除),最好使用匹配的字段命名所有带@Mock注释的字段,否则Mockito可能会混淆,并且不会发生注入。
注2:如果@InjectMocks实例之前没有初始化,并且有一个无参数的构造函数,那么它将被这个构造函数初始化。
如果您有多个服务,并且希望在基于spring的环境中用mock - object替换dao,我建议使用springckito: https://bitbucket.org/kubek2k/springockito/wiki/Home
在这里也有提到:向Spring bean中注入mock mock
你的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;
在你的@Test或@Before方法中,你可以用标准的Mockito方式设置你的mock:
Mockito.doReturn(null).when(mockedCountyDao).selectFromDB();
使用静态方法MockitoAnnotations.initMocks(Object)
来引导整个过程。
我不知道它是如何工作的,因为我没有浏览源代码,但我会实现它像这样:
- 用
@Mock
注释扫描传递的Object
类的成员变量。 - 为每个类创建一个mock,并将其设置为该成员。
- 用
@InjectMocks
注释扫描传递的Object
类的成员变量。 - 扫描所找到的每个成员的类,寻找可以被(2)中创建的模拟对象之一注入的成员(也就是说,字段是父类/接口,或与模拟对象声明的类相同的类),并将其设置为该成员。
别介意,在线查看—InjectMocks注释将带有@Mock注释的任何内容视为字段,并且是静态作用域(类范围),因此我确实无法保证mock将转到正确的服务。这在某种程度上是尝试在功能级别而不是类级别进行单元测试的思想实验。我想我还是用Spring自动装配这些东西吧