如何用静态方法模拟?

时间:2020-03-06 14:55:20  来源:igfitidea点击:

我是模拟对象的新手,但是我知道我需要让我的类实现接口才能模拟它们。

我遇到的问题是,在我的数据访问层中,我想拥有静态方法,但是不能在接口中放置静态方法。

最好的办法是什么?我应该只使用实例方法(这似乎是错误的)还是有其他解决方案?

解决方案

我将使用方法对象模式。拥有一个静态的实例,并在static方法中调用它。根据模拟框架,应该可以为测试创建子类。

即在类中使用静态方法有:

private static final MethodObject methodObject = new MethodObject();

public static void doSomething(){
    methodObject.doSomething();
}

并且方法对象可以是一个非常简单,易于测试的对象:

public class MethodObject {
    public void doSomething() {
        // do your thang
    }
}

是的,我们使用实例方法。静态方法基本上说:"有一种方法可以实现此功能,它不是多态的。"模拟依赖于多态性。

现在,如果静态方法在逻辑上不关心我们使用的是哪种实现,则它们可能能够将接口用作参数,或者可能完全不与状态进行交互而工作,但否则我们应该使用实例(并且可能是依赖项)注射以将所有东西连接在一起)。

尽可能使用实例方法。

在不可能使用实例方法的地方,使用公共静态Func T,U

我们可能试图在一个太深的起点进行测试。无需创建测试即可分别测试每种方法;私有和静态方法应通过调用公共方法进行测试,然后再依次调用私有和静态方法。

因此,可以说代码是这样的:

public object GetData()
{
 object obj1 = GetDataFromWherever();
 object obj2 = TransformData(obj1);
 return obj2;
} 
private static object TransformData(object obj)
{
//Do whatever
}

我们不需要针对TransformData方法编写测试(并且不需要)。而是为GetData方法编写一个测试,以测试在TransformData中完成的工作。

我通过google找到了一个博客,其中包含一些有关如何执行此操作的出色示例:

  • 将类重构为实例类并实现接口。我们已经说过我们不想这样做。
  • 将包装实例类与具有委托的类一起用于静态类成员。执行此操作可以通过委托模拟静态接口。
  • 使用带有受保护成员的包装实例类,这些成员调用静态类这可能是最容易模拟/管理而不进行重构的方法,因为它可以直接继承和扩展。

一个简单的解决方案是允许通过setter更改静态类的实现:

class ClassWithStatics {

  private IClassWithStaticsImpl implementation = new DefaultClassWithStaticsImpl();

  // Should only be invoked for testing purposes
  public static void overrideImplementation(IClassWithStaticsImpl implementation) {
     ClassWithStatics.implementation = implementation;
  }

  public static Foo someMethod() {
    return implementation.someMethod();
  }

}

因此,在测试设置中,我们可以通过一些模拟接口调用overrideImplementation。好处是我们不需要更改静态类的客户端。缺点是我们可能会有一些重复的代码,因为我们将不得不重复静态类的方法及其实现。但是有时静态方法可以使用提供基本功能的ligther接口。

我们遇到的问题是,当我们使用第三方代码时,它是从一种方法中调用的。我们最终要做的是将它包装在一个对象中,并调用它与dep inj一起传递,然后单元测试可以模拟第3方的静态方法使用它来调用setter。