Java 在创建某种工厂时,避免静态的可测试性方法

Java 在创建某种工厂时,避免静态的可测试性方法,java,unit-testing,Java,Unit Testing,在重构一些代码时,我发现有一个new调用创建了一个具体的类 我在寻找一种方法来避免创建一个具体类并提高可测试性的调用,所以我创建了一种工厂,负责返回一个实例。然后,我使用Spring构造函数注入,将工厂注入测试中的系统 然而,现在我面临一个问题,即如何在工厂中使该方法保持静态,同时又具有良好的可测试性。但是,根据Misko Hevery的说法,我不清楚如何删除对new的调用、进行良好的单元测试以及避免静态方法调用 这是从使用工厂的类中提取的。我正在测试此类中使用构造(和模拟)columnFami

在重构一些代码时,我发现有一个
new
调用创建了一个具体的类

我在寻找一种方法来避免创建一个具体类并提高可测试性的调用,所以我创建了一种工厂,负责返回一个实例。然后,我使用Spring构造函数注入,将工厂注入测试中的系统

然而,现在我面临一个问题,即如何在工厂中使该方法保持静态,同时又具有良好的可测试性。但是,根据Misko Hevery的说法,我不清楚如何删除对new的调用、进行良好的单元测试以及避免静态方法调用

这是从使用工厂的类中提取的。我正在测试此类中使用构造(和模拟)columnFamilyTemplate的方法:

受保护的AlertFieldMatcher(ColumnFamilyTemplateBuilder ColumnFamilyTemplateBuilder、键空间键空间、,
T2JSONUTIL接口jsonUtil){
this.columnFamilyTemplate=columnFamilyTemplateBuilder.build(键空间,CF\u警报);
this.jsonUtil=jsonUtil;
}


这就是工厂,我现在必须在测试中模拟SUT中的方法(如上所述):

公共类DefaultColumnFamilyTemplateBuilder
实现ColumnFamilyTemplateBuilder{
@凌驾
公共列FamilyTemplate生成(键空间键空间,
字符串(列系列){
ColumnFamilyTemplate内置模板=
新节俭家庭模板
(键空间,
我的家人,
StringSerializer.get(),
StringSerializer.get());
返回builtTemplate;
}
...
}
我看到的唯一选择是保持我的Factory类型对象不变,即不使该方法为静态。

如果要从应用程序中删除“new”,则需要一些机制来代表您创建对象。您可能需要检查三种机制

第一个是依赖注入。DI容器允许您采用更基于接口的方法,并选择在运行时使用什么实现。Spring是最流行的DI容器,而CDI是新的“标准”。DI很好,但它不一定是您希望在项目后期引入的类型

第二种机制是JavaServiceLoader,它允许您通过在类路径中添加和删除文件来更改组件的实现。你可能会觉得这有点棘手

最后一种机制是使用静态方法(!!!!)读入一个属性,该属性是工厂对象的类名,并使用class.forName().newInstance()为您创建工厂对象。这可能是最简单的方法。它为您提供了一个接缝,可以将新的模拟工厂注入其中


避免静态是一个好主意,但它们有自己的位置。如果您了解所涉及的权衡,请使用它们。

您不需要明确创建工厂

将创建新实例的过程提取到类中的受保护方法,与创建新ThriftColumnFamilyTemplate(…)作为默认实现完全相同


在单元测试中,sut将是类的部分模拟版本,模拟工厂方法,而不是真实的类。使用这种方法,唯一未测试的代码将是工厂方法,即一行代码。对于您可以使用的部分模拟。

您的代码有什么问题?为什么要将工厂方法设置为静态?你不应该这样做(为了可测试性)的原因是你可以注入另一个工厂,它实例化一个测试对象,而不是一个真实的。我这样问是因为我没有一个强有力的答案给我的老板,当我建议可能使它成为静态的时候。保持原样,正如您所说(我认为),我能够模拟DefaultColumnFamilyTemplateBuilder,并在测试中使用模拟实现。作为一个静态的,我想我不能这么做。我还注意到,我混合了使用As name的术语,这意味着已知的构建器模式和工厂对象。我认为测试静态方法没有任何问题effects@mishadoff我不是在测试工厂,而是在测试使用它的东西。此外,工厂中的
build
方法被编码到接口中,该接口从Java 7开始就不能包含静态方法。只要我想模仿工厂,我就需要一个非静态的卫理公会。我确实使用Spring将我的工厂注入到构造函数中。我的问题是,如果我最终将该方法转换为静态方法,那么我将使用Powermock模拟静态方法,或者我将其保持原样并将我的工厂编码为一个接口我会说将其编码为一个接口。Spring为您完成了繁重的工作,测试应该很简单。我想说的是,如果你在做DI,那么使用statics和new的整个问题就会消失——这就是我要告诉你老板的。