2013-10-28 29 views
1

当重构一些代码时,我发现我有一个创建具体类的new调用。当创建一种工厂时避免静态方法的可测试性

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

但是现在我面临一个问题,就是在我的工厂中使该方法变为静态,同时具有良好的可测试性。据米斯科Hevery,Static Methods are Death to testability然而,我不知道该怎么做才能删除对新的调用,有良好的单元测试,并避免静态方法调用。

这是使用工厂的类的摘录。我测试在这个类中的方法利用构造(戏弄)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

我在问,因为我没有给我的老板一个强有力的答案,当建议可能使其静态。保持原样,就像你说的(我认为),我能够模拟DefaultColumnFamilyTemplateBuilder并在我的测试中使用模拟实现。作为一个静态我想我不能那样做。 – Crowie

+0

我也注意到我混合了一些名词,暗示着已知的Builder模式和一个Factory对象 – Crowie

回答

1

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

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

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

最后一个机制是使用一个静态方法(!!!!)读入属性,该属性是工厂对象的类名,并使用Class.forName()。newInstance()创建工厂对象为你。这可能是最简单的方法。它为您注入一个新的模拟工厂。

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

+0

谢谢Ian。我使用Spring注入工厂到构造函数中。对我来说,问题是如果我最终将方法转换为静态,在这种情况下,我将使用Powermock来嘲弄静态,或者保持原样,并将我的Factory编码为接口 – Crowie

+0

我会说让它编码到一个接口。 Spring为你做了繁重的工作,测试应该很简单。我会说,如果你正在做DI,那么使用静态和新的消失的整个问题 - 这就是我要告诉你的老板。 –

1

您不需要明确创建工厂。

将新实例的创建解压缩到类中的受保护方法中,就像创建factory method一样,但提供new ThriftColumnFamilyTemplate(...)作为默认实现。

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