35

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

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

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

4

7 回答 7

27

是的,您使用实例方法。静态方法基本上是说,“有一种方法可以完成这个功能——它不是多态的。” 模拟依赖于多态性。

现在,如果您的静态方法在逻辑上不关心您正在使用什么实现,它们可能能够将接口作为参数,或者可能在根本不与状态交互的情况下工作 - 但否则您应该使用实例(并且可能依赖注入将所有东西连接在一起)。

于 2008-09-30T13:43:50.963 回答
27

通过谷歌找到了一个博客,里面有一些很好的例子来说明如何做到这一点:

  1. 将类重构为实例类并实现接口。

    你已经说过你不想这样做。

  2. 对静态类成员使用带有委托的包装器实例类

    这样做,您可以通过委托模拟静态接口。

  3. 使用带有受保护成员的包装器实例类,这些成员调用静态类

    这可能是最容易模拟/管理而无需重构的,因为它可以继承和扩展。

于 2008-09-30T13:59:48.493 回答
22

我会使用方法对象模式。有一个 this 的静态实例,并在静态方法中调用它。根据您的模拟框架,应该可以子类化进行测试。

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

private static final MethodObject methodObject = new MethodObject();

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

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

public class MethodObject {
    public void doSomething() {
        // do your thang
    }
}
于 2008-09-30T13:41:55.603 回答
5

您可能试图在太深的起点进行测试。不需要创建测试来单独测试每个方法;私有和静态方法应该通过调用公共方法进行测试,然后依次调用私有和静态方法。

所以可以说你的代码是这样的:

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

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

于 2008-09-30T13:55:01.920 回答
4

尽可能使用实例方法。

在无法使用实例方法的情况下,使用 public static Func[T, U](可以替代模拟函数的静态函数引用)。

于 2008-09-30T13:44:57.780 回答
0

一个简单的解决方案是允许通过 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使用一些模拟接口进行调用。好处是您不需要更改静态类的客户端。缺点是您可能会有一些重复的代码,因为您必须重复静态类的方法及其实现。但有时静态方法可以使用提供基本功能的更轻的接口。

于 2008-09-30T14:13:06.497 回答
0

The problem you have is when you're using 3rd party code and it's called from one of your methods. What we ended up doing is wrapping it in an object, and calling passing it in with dep inj, and then your unit test can mock 3rd party static method call the setter with it.

于 2009-07-15T18:17:43.237 回答