如何用静态方法模拟?
我是模拟对象的新手,但是我知道我需要让我的类实现接口才能模拟它们。
我遇到的问题是,在我的数据访问层中,我想拥有静态方法,但是不能在接口中放置静态方法。
最好的办法是什么?我应该只使用实例方法(这似乎是错误的)还是有其他解决方案?
解决方案
我将使用方法对象模式。拥有一个静态的实例,并在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。