服务中的模拟存储库

时间:2014-05-07 09:15:12

标签: design-patterns moq

我有一项服务,我想要测试而不使用"真正的"存储库,但是一个模拟存储库。 主程序

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;
    }
}
在测试中,我不想真正保存客户。 使用mock,我可以创建存储库

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

但我如何使用此模拟存储库而不是真正的存储库来调用服务?

如果可能的话,我不想像新的ServiceManager(存储库)那样创建服务;

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

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来保存模拟。 这是一般采用的最佳解决方案吗?

2 个答案:

答案 0 :(得分:1)

经典的方法是使用控制反转(这意味着ServiceManager不再控制创建Repository),通常由依赖注入实现(这意味着依赖关系Repository被&#34;注入&#34;到SericeManager)。


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

  

如果可能的话,我不想像新的ServiceManager(存储库)那样创建服务;

为实现此目的,您可以在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和其他类&#34 ;清洁&#34;手动创建dependend类的实例。

答案 1 :(得分:0)

  

如果可能的话,我不想像新的ServiceManager(存储库)那样创建服务;

如果这是一个绝对的要求,你需要使用像Fakes / Moles这样的重型工具来将一个moled存储库变成你的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,然后将ServiceManagerRepository的依赖关系减少到接口。您的moq仓库为var rep = new Mock<IRepository>();,依赖关系变为private readonly IRepository _repository;