2012-01-20 138 views
3

我目前正在尝试改进用Java编写的遗留系统的可测试性。目前最为棘手的问题是存在无法嘲笑的“内部”依赖关系。解决这个问题非常简单:引入依赖注入。使用构造函数注入和默认构造函数是不好的?

不幸的是,代码库非常大,所以在整个应用程序中引入依赖注入将是一个巨大的努力,直到“引导”。对于每个我想测试的课程,我都需要改变另外的一百个(也许我在这里夸大了一点,但肯定会很多)类,这取决于已更改的组件。

现在我的问题:是否可以,使用两个构造函数,默认构造函数初始化实例字段的默认值和另一个允许注入依赖关系?使用这种方法有什么缺点吗?它将允许依赖注入以备将来使用,但仍不需要改变现有的代码(尽管被测试的类)。

当前代码(“内部”的依赖):

public class ClassUnderTest { 

    private ICollaborator collab = new Collaborator(); 

    public void methodToTest() { 
    //do something 
    collab.doComplexWork(); 
    //do something 
    } 

} 

在默认/ DI构造:

public class ClassUnderTest { 

    private ICollaborator collab; 

    public ClassUnderTest() { 
    collab = new Collaborator(); 
    } 

    public ClassUnderTest(ICollaborator collab) { 
    this.collab = collab; 
    } 

    public void methodToTest() { 
    //do something 
    collab.doComplexWork(); 
    //do something 
    } 

} 
+0

这对我来说看起来很不错。只要确保您可以使用实例字段,而不是在每次方法调用时重新实例化新实例。这两个片段并不等同。如果必须在每个方法调用时创建新实例,则注入协作者的工厂而不是注入协作者。 –

+0

哦,你当然是对的。当我创建这个例子时,我没有想到它。我将编辑示例。 – user1159435

+3

这被称为混蛋注射,并可能有问题:http://stackoverflow.com/questions/6733667/is-there-an-alternative-to-bastard-injection-aka-poor-mans-injection-via-defa –

回答

0

这是绝对正常,我这样做偶尔也,尤其是服务式班由于遗留代码或框架限制,缺省构造函数是必需的。

通过使用两个构造函数,您可以清楚地分离默认协作对象,同时仍允许测试注入模拟。您可以通过使第二个构造器包受保护并将单元测试保留在同一个包中来强化意图。

它不如完整的依赖注入模式,但这并不总是一个选项。

+0

非常感谢您的回答!我也想过要降低di构造函数的可见性。我不确定这种情况下最好的方法是什么。公共构造函数将允许在将来使用其他依赖关系实现的情况下更容易重用(这是整个依赖注入概念背后的想法,对吧?)。你是否看到公开的缺点? – user1159435

0

我认为这非常好。我会根据参数化构造默认构造函数,但这可能是一个风格和偏好的问题。

我会更加谨慎的是增加一个setCollaborator()函数,因为这会彻底改变ClassUnderTest的契约(和假设),如果从某人编写的代码调用这将导致奇怪的错误场景了解历史,没有正确阅读文档(或者根本没有任何文档......)