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; } }
SingletonDependedClass
testing(使用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的背景下对这个问题做了详细的分析 。 我会尽量总结一下我的观点:
- 如果你的Singleton具有重要的全局状态,不要使用Singleton。 这包括持久性存储,如数据库,文件等
- 在依赖Singleton对象的情况下,类名不是显而易见的,应该注入依赖关系。 将Singleton实例注入类的需求certificate了该模式的错误用法(参见第1点)。
- 假设Singleton的生命周期与应用程序相同。 大多数Singleton实现使用延迟加载机制来实例化自己。 这是微不足道的,他们的生命周期不太可能改变,否则你不应该使用Singleton。