【发布时间】:2010-09-14 06:15:53
【问题描述】:
我是模拟对象的新手,但我知道我需要让我的类实现接口才能模拟它们。
我遇到的问题是,在我的数据访问层中,我想拥有静态方法,但我不能将静态方法放在接口中。
解决这个问题的最佳方法是什么?我应该只使用实例方法(这似乎是错误的)还是有其他解决方案?
【问题讨论】:
标签: c# .net mocking interface static-methods
我是模拟对象的新手,但我知道我需要让我的类实现接口才能模拟它们。
我遇到的问题是,在我的数据访问层中,我想拥有静态方法,但我不能将静态方法放在接口中。
解决这个问题的最佳方法是什么?我应该只使用实例方法(这似乎是错误的)还是有其他解决方案?
【问题讨论】:
标签: c# .net mocking interface static-methods
我会使用方法对象模式。有一个 this 的静态实例,并在静态方法中调用它。根据您的模拟框架,应该可以子类化进行测试。
即在你的类中使用静态方法有:
private static final MethodObject methodObject = new MethodObject();
public static void doSomething(){
methodObject.doSomething();
}
您的方法对象可以是一个非常简单、易于测试的对象:
public class MethodObject {
public void doSomething() {
// do your thang
}
}
【讨论】:
是的,您使用实例方法。静态方法基本上是说,“有一种方法可以完成这个功能——它不是多态的。”模拟依赖于多态性。
现在,如果您的静态方法在逻辑上不关心您正在使用什么实现,它们可能能够将接口作为参数,或者可能根本不与状态交互 - 但否则您应该使用实例(并且可能依赖注入将所有内容连接在一起)。
【讨论】:
尽可能使用实例方法。
在无法使用实例方法的情况下使用 public static 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 中完成的工作。
【讨论】:
我找到了blog via 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。好处是您不需要更改静态类的客户端。缺点是您可能会有一些重复的代码,因为您必须重复静态类的方法及其实现。但有时静态方法可以使用提供基本功能的更轻的接口。
【讨论】:
您遇到的问题是当您使用第 3 方代码时,它是从您的一种方法调用的。我们最终做的是将它包装在一个对象中,并使用 dep inj 调用传递它,然后您的单元测试可以模拟 3rd 方静态方法调用 setter。
【讨论】: