我目前正在尝试提高用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)
这绝对没问题,我偶尔也这样做,特别是对于服务式类,由于遗留代码或框架约束,需要使用默认构造函数。
通过使用两个构造函数,您可以清楚地分离默认的协作者对象,同时仍允许测试注入模拟。您可以通过使第二个构造函数受到包保护来强化意图,并将单元测试保存在同一个包中。
它不像完整的依赖注入那么好,但这并不总是一种选择。
答案 1 :(得分:0)
我认为这完全没问题。我会根据参数化构造函数编写默认构造函数,但这可能是样式和首选项的问题。
我更加谨慎的是添加setCollaborator()
- 函数,因为这会彻底改变ClassUnderTest的契约(和假设),如果从某人编写的代码中调用,则会导致奇怪的错误情况。不知道历史,没有正确阅读文档(或者根本没有任何文档......)