C# 如何用静态方法模拟?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/153048/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 15:50:23  来源:igfitidea点击:

How to mock with static methods?

提问by brien

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?

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

采纳答案by Grundlefleck

I would use a method object pattern. Have a static instance of this, and call it in the static method. It should be possible to subclass for testing, depending on your mocking framework.

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

i.e. 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
    }
}

回答by Jon Skeet

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).

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

回答by Amy B

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.

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

回答by Carlton Jenke

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). Instead write a test for the GetData method that tests the work done in TransformData.

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

回答by Rick Minerich

I found a blog via googlewith some great examples on how to do this:

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

  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.

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

    您已经声明不想这样做。

  2. 将包装实例类与静态类成员的委托一起使用

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

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

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

回答by asterite

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 overrideImplementationwith some mocked interface. 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.

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

回答by dstarh

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.

您遇到的问题是当您使用 3rd 方代码并且它是从您的方法之一调用时。我们最终做的是将它包装在一个对象中,并使用 dep inj 调用传入它,然后您的单元测试可以模拟 3rd 方静态方法用它调用 setter。