【问题标题】:How to mock with static methods?如何用静态方法模拟?
【发布时间】:2010-09-14 06:15:53
【问题描述】:

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

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

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

【问题讨论】:

    标签: c# .net mocking interface static-methods


    【解决方案1】:

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

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

    private static final MethodObject methodObject = new MethodObject();
    
    public static void doSomething(){
        methodObject.doSomething();
    }
    

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

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

    【讨论】:

    • 你对那个模式有什么好的参考吗?我不知道该怎么做。
    • 错误,实际上没有。我不确定我是否起了这个名字,或者它被认为更像是一个习语而不是一种模式,但我看不到 Google 提供的任何体面的参考资料。不过会继续寻找。
    • 谢谢,这个例子帮助我理解了你的意思。
    • 这样做实际上扼杀了所有关于使用静态方法的想法。
    • 这不是叫单例吗?
    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

      尽可能使用实例方法。

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

      【讨论】:

        【解决方案4】:

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

        假设你的代码是这样的:

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

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

        【讨论】:

          【解决方案5】:

          我找到了blog via google,上面有一些很好的例子来说明如何做到这一点:

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

            你已经声明不想这样做了。

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

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

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

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

          【讨论】:

          • 太棒了,谢谢,第三个选项对我来说是完美的
          【解决方案6】:

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

          【讨论】:

          • 一个小点,如果要以静态方式访问,实现不是必须声明为静态的吗?
          【解决方案7】:

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-03-13
            • 2014-12-12
            • 2017-10-08
            相关资源
            最近更新 更多