我对如何为依赖项提供默认值以及如何处理它们的测试有一些疑问。 假设我的课程如下:
class MyService {
private AnotherService dependency;
...
}
由于这是遗留应用程序,因此没有依赖注入(即使是本地应用程序)。 因此,为了提供依赖性,有几种方法(例如构造函数,setter)。 但我想为这种依赖提供默认实现,但我不知道该怎么做。
我是通过
来做到的class MyService {
private AnotherService dependency = new AnotherServiceImpl();
...
}
但是在创建MyService时始终会初始化此依赖项。对于测试我不想要这个,因为我想提供模拟impl。我想像
这样的东西class MyService {
private AnotherService dependency;
private AnotherService getDependency() {
if(dependency == null) {
dependency = new AnotherService();
}
return dependency
}
setDependency(AnotherService dependency) {
this.dependency = dependency;
}
}
现在,如果首先通过getDependency()完成所有依赖调用,那么我认为依赖是以懒惰的方式加载的,我可以自己设置以进行测试。
我知道很难开始在遗留代码中引入依赖注入等更改,而这些代码已经没有。例如。如果我在构造函数中提供我的依赖项,依赖项实例化的问题只会向上移动一级。
第二个问题是如果现在只有一个实现,如何提供依赖关系。我正在使用Mockito,它的@InjectMocks可以将模拟注入私有领域。我想知道是否需要公开setDependency或构造函数arg依赖关系,并使用接口使其成为impl?现在不是过度工程吗?我不想仅为测试更改代码。
答案 0 :(得分:1)
一个常见的模式是重载你的构造函数:
class MyService {
private AnotherService dependency;
MyService() {
this(new AnotherServiceImpl());
}
MyService(AnotherService dependency) {
this.dependency = dependency;
}
...
}
通过调用默认构造函数,现有代码将像以前一样工作,而测试可以使用具有注入依赖性的构造函数。
答案 1 :(得分:0)
您可以使用Abstract Factory作为依赖项。
class MyService {
private AnotherService dependency;
private static ServiceFactory serviceFactory = ServiceFactory.getInstance();
...
public void action() {
...
AnotherService dependency = serviceFactory.getAnotherService();
...
}
}
单元测试应该更容易。只需从ServiceFactory类返回测试用例中的模拟实现。
在DI框架变得流行之前 - 抽象工厂模式随处可见。
答案 2 :(得分:0)
另一种选择是创建虚拟方法,而不是可以被测试覆盖
实施例: http://www.unit-testing.net/CurrentArticle/How-To-Remove-Data-Dependencies-In-Unit-Tests.html