【问题标题】:mock repository in service服务中的模拟存储库
【发布时间】:2014-05-07 18:05:53
【问题描述】:

我有一项服务,我想在不使用“真实”存储库的情况下进行测试,而是使用模拟存储库。 主程序

ServiceManager service = new ServiceManager();
Customer c = new Customer();
//set customer properties
service.Save(c);

服务

public class ServiceManager
{
    public bool Save(Customer customer)
    {
        Repository rep = new Repository();
        bool res = rep.Save((customer));

        return res;
    }
}

在测试中,我不想真正拯救客户。 使用模拟,我可以创建存储库

var rep = new Mock<Repository>();
rep.Setup(x => x.Save(customer)).Returns(true);

但是如何使用这个模拟存储库而不是真实存储库调用测试服务?

如果可能的话,我不想创建像 new ServiceManager(repository) 这样的服务;

另一种方法是使用存储库工厂,如果我们在测试中返回模拟,而在现实世界中返回真实存储库,例如

public static class repositoryFactory
{
    private static Repository mockRepository;
    public static void setRepository(Repository rep){
        mockRepository = rep;
    }

    public static Repository getRepository(){
        if (mockRepository == null)
            return new Repository();
        else
            return mockRepository;
    }
}

在这种情况下,在测试中我使用 setRepository 来保存模拟。 一般采用的最佳解决方案是什么?

【问题讨论】:

    标签: design-patterns moq


    【解决方案1】:

    经典的方法是使用控制反转(这意味着ServiceManager不再控制创建Repository),通常通过依赖注入实现(这意味着依赖Repository 被“注入”到SericeManager 中)。


    你似乎已经知道了,因为你写了

    如果可能的话,我不想创建像 new ServiceManager(repository) 这样的服务;

    为了实现这一点,您可以在ServiceManager 的构造函数中使用可选参数,例如:

    public class ServiceManager
    {
        private readonly IRepository rep;
    
        public ServiceManager(IRepository rep=null)
        {
             _rep = rep ?? new Repository();      
        }
    
        public bool Save(Customer customer)
        {
            bool res = _rep.Save((customer));
            return res;
        }
    }
    

    能够在您的应用程序中简单地使用new ServiceManager(),并在您的测试中使用new ServiceManager(repositoryMock)


    但是,如果您使用 IOC-Container(例如 StructureMap),则注入依赖项非常简单:您可以将对象的创建留给 IOC-Container,并让您的 ServiceManager 和其他类“干净”地创建手动依赖类的实例。

    【讨论】:

      【解决方案2】:

      如果可能的话,我不想创建像 new ServiceManager(repository) 这样的服务;

      如果这是绝对要求,您将需要使用像 Fakes / Moles 这样的重手工具来将一个被篡改的存储库破坏到您的 ServiceManager SUT 中。

      但是,由于它被标记为 moq,如果您确实解耦了您的依赖关系(例如通过 Setter 构造函数注入),那么您可以单独进行单元测试和 Mock。编写可测试代码的开销很小。

      public class ServiceManager
      {
          private readonly Repository _repository;
      
          public ServiceManager(Repository repository)
          {
              _repository = repository;
          }
      
          public bool Save(Customer customer)
          {
              bool res = _repository.Save((customer));
      
              return res;
          }
      }
      

      您的单元测试现在将能够创建 ServiceManager(SUT)并注入 Mocked 存储库。

      更好的办法是将存储库抽象为接口IRepository,然后将ServiceManager 的依赖减少到Repository 对接口的依赖。然后,您的起订量仓库为 var rep = new Mock&lt;IRepository&gt;();,依赖项变为 private readonly IRepository _repository;

      【讨论】:

        猜你喜欢
        • 2020-04-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-02-13
        • 1970-01-01
        • 1970-01-01
        • 2014-03-03
        • 1970-01-01
        相关资源
        最近更新 更多