摘要:本文针对 SpockFramework
如何测试使用 Guice
注入的服务进行讲解。
概述
当前 Java
的开发都离不开依赖注入,目前较为流行的轻量级注入框架是 Guice
。当使用依赖注入后,进行单元测试时就会面对如何解决注入的依赖的问题。
在进行单元测试的时候,我们往往需要尽可能的将测试单元化,也就是说所有和待测试的内容无关的都要进行模拟,有点类似于做试验中的单一变量原则,为了验证某一个条件对结果的影响,必须在保证其他条件都不变的情况下调整带测变量。而测试也应该尽可能的将待测目标所依赖的内容隔离开,通过模拟这些依赖的输出达到尽可能的测试待测目标的所有可能出现的情况。
这样就要求我们能够在测试中对注入的依赖进行模拟。因此我们总结一下需要在测试中解决的问题
- 在测试中实现依赖注入
- 对注入的实现进行
Mock
或者Spy
- 在测试中
Mock
或者Spy
注入的对象的某些行为
本文内容均参考 官方注入文档 以及 Github
上相应的案例。
注入的依赖的外部模拟
我们知道 Guice
的注入方式有很多种,为了能够实现对注入的 Mock
, 我们不能使用原有的注入方法。而需要重新注入。
因为我们将要在 Guice 注入的时候进行 Mock
,所以我们首先要解决的问题是,如果在 spec
之外的地方进行 Mock
,Spockframework
为我们提供了一个方法 DetachedMockFactory
。该工厂方法能够实现外部 Mock
。我们通过其 JavaDoc
能够大概了解其用法
This factory allows the creations of mocks outside of a Specification,
e.g., in a Spring configuration.In order to be usable those Mocks must be manually attached to the
Specification using MockUtil.attachMock(Object, Specification) and
detached afterwards MockUtil.detachMock(Object).Maven: org.spockframework:spock-core:1.1-groovy-2.4
1 | private DetachedMockFactory factory = new DetachedMockFactory(); |
通过上述代码,我们就能在任意位置 Mock
需要测试的类了。
使用 Guice Module
在使用 Guice
的时候,我们一般都会使用一个 Module
来统一进行注入,在 Spockframework
中,我仍然使用这种方法,而且 Spockframework
提供一个注解来应用 Guice
的 Module
,该注解为 UserModules
。
1 | (value = [MockBinderModule]) |
我们在 MockBinderModule
把我们上面所说的 Mock
的实现注入到接口中。比如我们有接口 TestService
,而实现是 TestServiceImpl1
,我们需要 Mock
实现,那么我就进行如下配置:
1 | (value = [MockBinderModule]) |
通过 DetachedMockFactory
的文档,我们知道,虽然我们在外部进行了 Mock
,但是实际上我们通过注入使用其实例的时候,并没有真正加载 Mock
的实例,我们需要手动加载 those Mocks must be manually attached to the Specification using MockUtil.attachMock
,然后手动卸载。
Spy 待测对象的注入
通常我们会 Mock
待测对象的依赖,然后对于待测对象,如果希望能够 在测试某些方法的时候,Mock
其他方法,我们也可以使用 Spy
监控待测对象,当然待测对象可以注入真实的实例。
私有函数的 Mock
有时候我们有需求在测试某一个 Public
方法的时候,不希望收到 某个 Private
方法影响,这时候最好就是将其 Mock
起来,但是实际上这是做不到。很多然讨论过这个话题,可以参考:
这里个人采用了如下方法:
- 尽量不
Mock
私有方法,私有的方法在共有方法一并测试 - 如果有些方法必须要测而且要
Mock
,那么该方法加入标签/* private -> testing */