在重构一些代码时,我发现我有一个new
调用,它创建了一个具体的类。
我一直在寻找一种方法来避免调用创建具体类并提高可测试性,因此我创建了一种Factory,它负责返回一个实例。然后,我使用Spring构造函数注入,将工厂注入到受测系统中。
然而,现在我遇到了一个问题,即在我的工厂中使该方法是静态的,同时具有良好的可测试性。根据Misko Hevery,Static Methods are Death to testability然而,我不清楚如何删除对new的调用,进行良好的单元测试,并避免静态方法调用。
这是使用工厂的类的摘录。我正在测试这个类中使用构造(和模拟)columnFamilyTemplate的方法:
protected AlertFieldMatcher(ColumnFamilyTemplateBuilder columnFamilyTemplateBuilder, Keyspace keyspace,
T2JsonUtilInterface jsonUtil) {
this.columnFamilyTemplate = columnFamilyTemplateBuilder.build(keyspace, CF_ALERT);
this.jsonUtil = jsonUtil;
}
这是工厂,我现在必须在SUT中测试方法(上图):
public class DefaultColumnFamilyTemplateBuilder
implements ColumnFamilyTemplateBuilder {
@Override
public ColumnFamilyTemplate<String, String> build(Keyspace keyspace,
String columnFamily) {
ColumnFamilyTemplate<String, String> builtTemplate =
new ThriftColumnFamilyTemplate<String, String>
(keyspace,
columnFamily,
StringSerializer.get(),
StringSerializer.get());
return builtTemplate;
}
...
}
我看到的唯一选择是保持我的工厂类型对象不变,即不使方法静态。
答案 0 :(得分:1)
如果您要从应用程序中删除“new”,则需要一些代表您创建对象的机制。您可能想要查看三种机制。
首先是依赖注入。 DI容器允许您采用更基于接口的方法,并选择在运行时使用的实现。 Spring是最受欢迎的DI容器,而CDI是新的“标准”。 DI很好,但它不一定是你想在项目后期引入的那种东西。
第二种机制是Java ServiceLoader,它允许您通过在类路径中添加和删除文件来更改组件的实现。你可能会发现这有点繁琐。
最后一种机制是使用静态方法(!!!!)读取属性,该属性是工厂对象的类名,并使用Class.forName()。newInstance()来创建工厂对象您。这可能是最简单的方法。它为您提供了一个接缝,可以将新的模拟工厂注入其中。
避免静力学是一个好主意,但他们有自己的位置。如果您了解所涉及的权衡,请使用它们。
答案 1 :(得分:1)
您无需明确创建工厂。
将新实例的创建提取到类中的受保护方法,与创建factory method但提供new ThriftColumnFamilyTemplate(...)
默认实现完全相同。
在你的单元测试中,你的sut将是类的部分模拟版本,模拟工厂方法,而不是真正的类。使用这种方法,唯一未经测试的代码将是工厂方法,即单行。对于部分模拟,您可以使用EasyMock IMockBuilder。