1

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

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

但是现在我面临一个问题,即在我的工厂中使该方法成为静态同时具有良好的可测试性。根据 Misko Hevery 的说法,静态方法是可测试性的死亡,但是我不清楚如何删除对 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;
   }

   ...
}

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

4

2 回答 2

1

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

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

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

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

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

于 2013-10-28T16:59:20.013 回答
1

您不需要显式创建工厂。

将新实例的创建提取到类中的受保护方法中,就像您创建工厂方法但提供new ThriftColumnFamilyTemplate(...)默认实现一样。

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

于 2013-11-05T13:08:27.297 回答