【问题标题】:UnitTesting Static Classes单元测试静态类
【发布时间】:2009-06-10 03:25:56
【问题描述】:

情景。语言 C#,使用 VS2008 单元测试框架进行单元测试

我有一个带有静态构造函数和 2 个方法的静态类。 我编写了 4 种测试方法来测试整个班级。 我的静态构造函数有一些重要的初始化。

现在,如果我串联运行所有 4 个单元测试用例,静态构造函数将是 仅在开始时调用。在每个测试用例结束时,没有这样的事情

称为静态析构函数,因此构造函数中的状态信息被传递到 下一个单元测试用例也是。解决方法是什么。

【问题讨论】:

    标签: c# .net unit-testing


    【解决方案1】:
    Type staticType = typeof(StaticClassName);
    ConstructorInfo ci = staticType.TypeInitializer;
    object[] parameters = new object[0];
    ci.Invoke(null, parameters);
    

    来自http://colinmackay.scot/2007/06/16/unit-testing-a-static-class/

    【讨论】:

    • 嘿看,这个问题的实际答案,而不是“不要那样做”。
    • 效果很好,但是我必须在类中手动声明一个静态的空构造函数(即使通常不需要它)。
    • 静态构造函数为什么要用参数?我们可以叫它ci.Invoke(null, null);吗?
    • 如果您有任何已声明但未在其声明中分配值的静态字段,这将不起作用。例如对于static class API { static int timeout = 5000, static string lastError; },以这种方式调用静态构造函数将重置timeout,但lastError 将保持之前测试中的状态。我发现的唯一解决方法是编辑类以初始化所有字段,例如static string lastError = null
    • 该死的。此外,public static bool IsConnected { get; set; } 等自动属性不会以这种方式重置。因此,如果您的最后一个测试将其设置为“true”,即使 bool 的默认值为 false,但在此行之后的下一次运行,它仍将是“true”,而不是第一次测试最初的“false”。
    【解决方案2】:

    最简单的解决方案是向您的静态类添加一个“重置”方法,这将具有破坏和重建它的等效行为。

    您在此处使用静态类可能是有正当理由的。但是,由于静态不能很好地配合单元测试,我通常会寻找替代设计。

    【讨论】:

      【解决方案3】:

      我会将初始化从静态构造函数移至构造函数调用的方法。通过将此方法设为internal,您可以从测试中调用此方法来重新初始化该类。

      public static class MyClass
      {
         public static MyClass()
         {
            initialize();
         }
      
         internal static void initialize()
         {
            // Do initialization (and cleanup if necessary)
         }
      
         public static void Method1() {}
         public static void Method2() {}
      }
      

      要调用内部方法,您需要使用 InternalsVisibleTo 属性,如this blog 中所述。

      您也可以将其设为私有,但随后您需要使用反射来调用它。

      但正如 Andrew Shepherd 所说,您还应该检查静态类是否是该类的最佳设计。

      【讨论】:

        【解决方案4】:

        在不知道类的用法的情况下仅对用法进行评论会有点棘手,但无论如何我都会尝试一下。对我来说,以上听起来更像是一个气味而不是一个测试问题。

        静态类(就像单例一样)基本上是全局函数/变量的集合,这在 oop 中通常是一件坏事。我想说的是尝试测试测试问题(尽管现在可能是最简单的)只是解决症状而不是问题。

        如果您真的需要静态类,或者如果它只是当时解决问题的最简单方法,我建议您考虑一下设计

        【讨论】:

          【解决方案5】:

          好吧,您没有指定您使用的是哪种语言,但是如果有办法从测试文件中打开您的静态类,那么我会向它添加一个假析构函数,您可以在每次调用之后调用它测试。这样,“析构函数”就保留在测试类中,并且不在您的生产代码中。

          【讨论】:

            【解决方案6】:

            您可以使用能够模拟静态类的Typemock's Isolator,因此在每个测试中您都可以“定义”静态将如何运行。

            虽然它不是免费产品。

            【讨论】:

              【解决方案7】:

              听起来您正在尝试测试静态构造函数。这似乎是个坏主意。

              考虑将初始化逻辑提取到一个单独的(非静态)类中。

              为了便于讨论,假设您的静态类名为 MySingleton,假设您创建了一个名为 MyInitializer 的新类,并带有一个 Execute 方法。 MySingleton 的静态构造函数可以实例化 MyInitializer 并调用 Execute,它会完成所有初始化。

              然后您的生产代码可以使用 MySingleton,而忽略 MyInitializer。另一方面,您的测试可以忽略 MySingleton,并愉快地为每个测试创建一个新的 MyInitializer 实例,每次都重新开始。

              【讨论】:

                【解决方案8】:

                为了完整起见,如果您需要重置静态类的非公共字段/变量,也可以通过反射来实现。

                using System.Reflection; // or Mono.Reflection
                
                public static class MyClass{
                    private static string myString;
                }
                
                var newValue = "Potatoes";            
                var field = typeof(MyClass).GetField("myString", BindingFlags.Static | BindingFlags.NonPublic);
                field.SetValue(null, newValue); // the first null is because the class is static, the second is the new value
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2011-11-11
                  • 2021-11-06
                  • 2016-09-07
                  • 2019-05-11
                  • 1970-01-01
                  • 2011-08-03
                  • 2011-08-23
                  • 1970-01-01
                  相关资源
                  最近更新 更多