unit testing

我用Visual Studio Team Editiontesting框架准备了一些自动testing。 我想要一个testing连接到数据库按照正常的方式在程序中完成:

string r_providerName = ConfigurationManager.ConnectionStrings["main_db"].ProviderName; 

但是,我正在接受这一行的例外。 我想这是因为ConfigurationManager是一个单身人士。 你怎么能用unit testing解决单身问题?


感谢您的答复。 他们都非常有教育意义。

看看Googletesting博客 :

  • 使用dependency injection来避免单例
  • 单身人士是病理性的说谎者
  • 单身人士的根本原因
  • 所有的单身人士都去了哪里?
  • 清洁的代码会谈 – 全局状态和单身
  • dependency injection 。

并且:

  • 一旦不够
  • 高性能的单身人士

最后,Misko Hevery在他的博客上写了一个指南: Writing Testable Code 。

你可以使用构造函数dependency injection。 例:

 public class SingletonDependedClass { private string _ProviderName; public SingletonDependedClass() : this(ConfigurationManager.ConnectionStrings["main_db"].ProviderName) { } public SingletonDependedClass(string providerName) { _ProviderName = providerName; } } 

这允许您在testing期间将连接string直接传递给对象。

此外,如果您使用Visual Studio Team Editiontesting框架,则可以使用参数private构造函数,并通过访问器testing该类。

其实我用嘲讽解决了这样的问题。 例:

你有一个依赖于单例的类:

 public class Singleton { public virtual string SomeProperty { get; set; } private static Singleton _Instance; public static Singleton Insatnce { get { if (_Instance == null) { _Instance = new Singleton(); } return _Instance; } } protected Singleton() { } } public class SingletonDependedClass { public void SomeMethod() { ... string str = Singleton.Insatnce.SomeProperty; ... } } 

首先SingletonDependedClass需要重构,以Singleton实例作为构造参数:

 public class SingletonDependedClass { private Singleton _SingletonInstance; public SingletonDependedClass() : this(Singleton.Insatnce) { } private SingletonDependedClass(Singleton singletonInstance) { _SingletonInstance = singletonInstance; } public void SomeMethod() { string str = _SingletonInstance.SomeProperty; } } 

SingletonDependedClasstesting(使用Moq模拟库 ):

 [TestMethod()] public void SomeMethodTest() { var singletonMock = new Mock<Singleton>(); singletonMock.Setup(s => s.SomeProperty).Returns("some test data"); var target = new SingletonDependedClass_Accessor(singletonMock.Object); ... } 

书中的示例 : 使用遗留代码有效地工作

这里也给出了相同的答案: https : //stackoverflow.com/a/28613595/929902

要在testing工具中运行包含单例的代码,我们必须放松单例属性。 以下是我们如何做到这一点。 第一步是向单例类添加一个新的静态方法。 该方法允许我们replace单例中的静态实例。 我们将其称为setTestingInstance

 public class PermitRepository { private static PermitRepository instance = null; private PermitRepository() {} public static void setTestingInstance(PermitRepository newInstance) { instance = newInstance; } public static PermitRepository getInstance() { if (instance == null) { instance = new PermitRepository(); } return instance; } public Permit findAssociatedPermit(PermitNotice notice) { ... } ... } 

现在我们有了这个setter,我们可以创build一个PermitRepository的testing实例并设置它。 我们想在我们的testing设置中编写这样的代码:

 public void setUp() { PermitRepository repository = PermitRepository.getInstance(); ... // add permits to the repository here ... PermitRepository.setTestingInstance(repository); } 

你在这里面临更普遍的问题。 如果滥用,单身人士妨碍testabiliy。

我在解耦devise的背景下对这个问题做了详细的分析 。 我会尽量总结一下我的观点:

  1. 如果你的Singleton具有重要的全局状态,不要使用Singleton。 这包括持久性存储,如数据库,文件等
  2. 在依赖Singleton对象的情况下,类名不是显而易见的,应该注入依赖关系。 将Singleton实例注入类的需求certificate了该模式的错误用法(参见第1点)。
  3. 假设Singleton的生命周期与应用程序相同。 大多数Singleton实现使用延迟加载机制来实例化自己。 这是微不足道的,他们的生命周期不太可能改变,否则你不应该使用Singleton。