C# 单元测试静态类

C# 单元测试静态类,c#,.net,unit-testing,C#,.net,Unit Testing,情景。语言C#,使用VS2008单元测试框架进行单元测试 我有一个静态类,带有一个静态构造函数和两个方法。 我编写了4种测试方法来测试整个类。 我的静态构造函数有一些重要的初始化 现在,如果我同时运行所有4个单元测试用例,静态构造函数将是 只在一开始打电话。在每个测试用例的末尾,都没有这样的事情 调用静态析构函数,因此构造函数中的状态信息会被带到 下一个单元测试用例也是。解决方法是什么。好吧,您没有指定使用哪种语言,但是如果有办法从测试文件中打开静态类,那么我会向其中添加一个伪析构函数,您可以在

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

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

现在,如果我同时运行所有4个单元测试用例,静态构造函数将是 只在一开始打电话。在每个测试用例的末尾,都没有这样的事情

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

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

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

这里使用静态类可能有一个合理的原因。但是,由于静态不能很好地与单元测试配合使用,我通常会寻找一种替代设计。

您可以使用能够模拟静态类的设计,因此在每个测试中,您可以“定义”静态的操作方式


不过,它不是免费的产品。

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

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

为了便于讨论,假设您的静态类名为MySingleton,并且假设您创建了一个名为MyInitializer的新类,其中包含一个Execute方法。MySingleton的静态构造函数可以实例化MyInitializer并调用Execute,执行所有初始化


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

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

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


如果您真的需要静态类,或者如果这似乎是当时解决问题的最简单方法,我建议您看看设计concidere,我会将初始化从静态构造函数移动到构造函数调用的方法。通过将此方法设置为内部方法,然后可以从测试中调用此方法来重新初始化类

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属性,如中所述

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

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

Type staticType = typeof(StaticClassName);
ConstructorInfo ci = staticType.TypeInitializer;
object[] parameters = new object[0];
ci.Invoke(null, parameters);

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

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

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