创建一种Factory时,避免使用静态方法进行可测试性

时间:2013-10-28 12:46:41

标签: java unit-testing

在重构一些代码时,我发现我有一个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;
   }

   ...
}

我看到的唯一选择是保持我的工厂类型对象不变,即不使方法静态。

2 个答案:

答案 0 :(得分:1)

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

首先是依赖注入。 DI容器允许您采用更基于接口的方法,并选择在运行时使用的实现。 Spring是最受欢迎的DI容器,而CDI是新的“标准”。 DI很好,但它不一定是你想在项目后期引入的那种东西。

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

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

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

答案 1 :(得分:1)

您无需明确创建工厂。

将新实例的创建提取到类中的受保护方法,与创建factory method但提供new ThriftColumnFamilyTemplate(...)默认实现完全相同。

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