如何在单元测试中隔离单例?

时间:2011-08-28 18:38:05

标签: c# unit-testing rhino-mocks nunit-2.5

我的程序中有一个静态类。在静态构造函数中,我创建了服务实例。服务代理是单身人士。

我必须为这个类编写单元测试,当然我想要隔离这个服务。 我该怎么办?

在我的项目中,我们使用Rhino.Mocks。

2 个答案:

答案 0 :(得分:3)

从单元测试的角度来看,单身人士存在问题。我假设使用Singleton的类是通过静态属性检索实例的:

class MyClass()
{
   public MyClass()
   {
      var myService = StaticFoo.MyServiceInstance;
   }
}

这相当于在本地创建一个具体的类实例,因为知道“如何到达”您的Singleton是您的类实现的一部分。你需要做的就是删除这些知识并注入这种依赖,就像你在非单例上注入其他依赖一样。最直接的方式是构造函数注入:

class MyClass()
{
   public MyClass(IService myService)
   {
     //..
   }
}

另一个需要的部分是确保服务中的所有接口方法/属性都定义为虚拟或定义服务实现的接口或抽象基类,并定义类MyClass正在使用的所有操作这项服务。这是必需的,因为大多数单元测试框架(包括Rhino-Mocks)只能模拟虚拟方法/属性。

我见过的另一种选择,但个人并不喜欢,在您的Singleton中引入一个setter,这样您就可以用单元测试所需的模拟对象“交换”具体类。此setter仅用于单元测试,可以标记为internal,因此程序集外部的类无权访问。然后,您可以使用InternalsVisibleTo属性为单元测试程序集创建一个特殊异常,以便它可以查看和使用setter。

这种方法的主要优点是,它需要较少的重构才能获得可测试的解决方案,但代价是“污染”静态Singleton支架的界面。因为在大多数情况下,首先不需要单身人士,我会考虑首先重构构造函数。

答案 1 :(得分:1)

您需要在您的类上拥有一个接受该服务实例的公共初始化方法。然后,您可以使用初始化方法注入模拟对象。