简体   繁体   English

如何用静态方法模拟?

[英]How to mock with static methods?

I'm new to mock objects, but I understand that I need to have my classes implement interfaces in order to mock them. 我是模拟对象的新手,但是我知道我需要让我的类实现接口才能模拟它们。

The problem I'm having is that in my data access layer, I want to have static methods, but I can't put a static method in an interface. 我遇到的问题是,在我的数据访问层中,我想拥有静态方法,但是不能在接口中放置静态方法。

What's the best way around this? 最好的办法是什么? Should I just use instance methods (which seems wrong) or is there another solution? 我应该只使用实例方法(这似乎是错误的)还是有其他解决方案?

Yes, you use instance methods. 是的,您使用实例方法。 Static methods basically say, "There is one way to accomplish this functionality - it's not polymorphic." 静态方法基本上说:“有一种方法可以实现此功能-它不是多态的。” Mocking relies on polymorphism. 模拟依赖于多态性。

Now, if your static methods logically don't care about what implementation you're using, they might be able to take the interfaces as parameters, or perhaps work without interacting with state at all - but otherwise you should be using instances (and probably dependency injection to wire everything together). 现在,如果您的静态方法在逻辑上不关心您使用的是哪种实现,则它们可能能够将接口用作参数,或者根本不与状态进行交互就可以工作-但否则您应该使用实例(并且可能依赖注入将所有内容连接在一起)。

I found a blog via google with some great examples on how to do this: 通过google找到了一个博客 ,其中包含一些有关如何执行此操作的出色示例:

  1. Refactor class to be an instance class and implement an interface. 将类重构为实例类并实现接口。

    You have already stated that you don't want to do this. 您已经说过您不想这样做。

  2. Use a wrapper instance class with delegates for static classes members 将包装实例类与具有静态类成员的委托一起使用

    Doing this you can simulate a static interface via delegates. 这样做,您可以通过委托模拟静态接口。

  3. Use a wrapper instance class with protected members which call the static class 将包装实例类与受保护的成员一起使用,这些成员调用静态类

    This is probably the easiest to mock/manage without refactoring as it can just be inherited from and extended. 这可能是最容易模拟/管理而不进行重构的方法,因为它可以直接继承和扩展。

I would use a method object pattern. 我将使用方法对象模式。 Have a static instance of this, and call it in the static method. 拥有一个静态的实例,并在static方法中调用它。 It should be possible to subclass for testing, depending on your mocking framework. 根据您的模拟框架,应该可以为测试创建子类。

ie in your class with the static method have: 即在您的类中使用静态方法有:

private static final MethodObject methodObject = new MethodObject();

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

and your method object can be a very simple, easily-tested: 并且您的方法对象可以是非常简单,易于测试的:

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

You might be trying to test at too deep a starting point. 您可能试图在一个太深的起点进行测试。 A test does not need to be created to test each and every method individually; 无需创建测试就可以分别测试每种方法。 private and static methods should be tested by calling the public methods that then call the private and static ones in turn. 私有和静态方法应通过调用公共方法进行测试,然后再依次调用私有和静态方法。

So lets say your code is like this: 所以可以说您的代码是这样的:

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

You do not need to write a test against the TransformData method (and you can't). 您不需要针对TransformData方法编写测试(并且不需要)。 Instead write a test for the GetData method that tests the work done in TransformData. 而是为GetData方法编写测试,以测试在TransformData中完成的工作。

Use instance methods where possible. 尽可能使用实例方法。

Use public static Func[T, U] (static function references that can be substituted for mock functions) where instance methods are not possible. 在不可能使用实例方法的地方,使用公共静态Func [T,U](可以代替模拟函数的静态函数引用)。

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. 我们最终要做的是将其包装在一个对象中,并调用它与dep inj一起传递,然后您的单元测试可以模拟第三方静态方法使用它来调用setter。

A simple solution is to allow to change the static class's implementation via a setter: 一个简单的解决方案是允许通过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();
  }

}

So in the setup of your tests, you call overrideImplementation with some mocked interface. 因此,在测试设置中,您overrideImplementation使用一些模拟接口来调用overrideImplementation The benefit is that you don't need to change clients of your static class. 好处是您无需更改静态类的客户端。 The downside is that you probably will have a little duplicated code, because you'll have to repeat the methods of the static class and it's implementation. 缺点是您可能会有一些重复的代码,因为您将不得不重复静态类的方法及其实现。 But some times the static methods can use a ligther interface which provide base funcionality. 但是有时静态方法可以使用提供基本功能的ligther接口。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM