默认依赖实现,如何处理没有DI框架?

时间:2012-03-02 09:15:23

标签: java unit-testing dependency-injection

我对如何为依赖项提供默认值以及如何处理它们的测试有一些疑问。 假设我的课程如下:

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?现在不是过度工程吗?我不想仅为测试更改代码。

3 个答案:

答案 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

相关问题