【问题标题】:Mocking and Singletons模拟和单例
【发布时间】:2012-06-25 21:22:20
【问题描述】:

我目前正在开发一个更大的 C# 项目。我已经编写了几个连接到数据库层的类,现在必须对它们进行测试。使用的测试框架是 Visual Studio Ultimate 之一。我得到了一个 Mock-layer 用于测试,但是我不确定如何使用它。

基本上我的方法是这样工作的:

public static void bla()
{
//This is a multithreaded singleton
Connection con = Connection.Instance;

//This raises a lot of Events 
con.SomeConnection.Send(new GetBla()); 
}

MockLayer 基本上是 ConnectionMock 并将它的所有方法实现为模拟。有没有办法让 con 成为 Mock 而无需以任何方式改变方法?

【问题讨论】:

    标签: c# testing mocking


    【解决方案1】:

    实际上,您可以使用反射来模拟单例。请参阅我的回答:

    How to Mock a Static Singleton?

    【讨论】:

      【解决方案2】:

      第一步是确定你想做什么......最重要的是确定你的 SUT(被测对象)

      有什么方法可以让 con 成为 Mock 而无需以任何方式改变方法?

      我不认为你可以做这样的事情,即使你能找到一种技术方法来做到这一点,也不推荐这样做。相反,您应该使用例如存储库对 DAL 层进行抽象。像这样的:

      interface IMyRepository
      {
         void Send(Bla bla);
      }
      

      现在您可以在您的类中使用 DI 来注入对该接口的引用。当你想编写单元测试时,你应该创建一个接口模拟。

      为了轻松创建模拟,我可以向您推荐以下工具:

      无论如何,在您的情况下,不更改代码测试代码的唯一方法是将连接字符串更改为虚拟数据库,然后运行集成测试

      很遗憾,我不得不告诉您,您的代码不适合测试,您应该重构代码以删除静态成员。

      我能告诉你的最佳建议是:阅读关于编写干净的测试友好代码的指南。

      看看以下链接:

      你有兴趣为你的代码编写测试是件好事,但由于你没有参加 TDD,这意味着首先编写测试,你编写代码时没有考虑可测试性,结果很简单:编写测试将是一个真正的 PITA,编写它们需要重构您的代码。

      我了解您不想重构代码,因为您不想破坏现有功能,这是从一开始就编写测试的最大好处之一,您将能够重构代码并运行测试确保你没有破坏任何东西

      【讨论】:

      • 是的,我最终重构了一切。很多工作,但我想我吸取了教训......
      【解决方案3】:

      简而言之,不,没有办法。这是使用静态类和单例对象的最大缺点之一。您已经定义了一个规则,即只能存在一个 Connection 对象,并且它始终必须是您指定的确切实例。创建一个 mock 并试图让所有代码都使用它会违反该规则。

      换句话说,为了模拟一个对象,您必须能够创建另一个实例并将您的实例替换为预期的实例。静态类(和单例)明确地阻止了这种情况的发生。

      更好的选择是使用依赖注入,这样你的“预期”连接类总是注册在真实环境中,你的模拟总是注册单元测试。

      【讨论】:

      • 从概念上看你是对的:应用单例模式指定应该只有一个类的一个实例和一个访问它的方法。这就是它的意义所在,这不是缺点,而是其理念的核心。然而在实践中,大多数实现并没有将规范强制执行到最后的结果。请参阅我的答案中的链接,了解如何通过反射注入模拟。请参阅stackoverflow.com/questions/4447939/…,了解如何防止这种情况发生。
      猜你喜欢
      • 1970-01-01
      • 2011-01-04
      • 2016-05-07
      • 1970-01-01
      • 2016-10-24
      • 2017-09-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多