Design patterns 服务中的模拟存储库

Design patterns 服务中的模拟存储库,design-patterns,moq,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) { Repos

我有一个服务,我希望测试不使用“真实”存储库,而是使用模拟存储库。 主程序

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);
在本例中,在测试中,我使用setRepository保存模拟。 通常采用的最佳解决方案是什么

如果可能,我不想创建像新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)并注入模拟存储库

更好的做法是将存储库抽象为一个接口,
IRepository
,然后将
ServiceManager
repository
的依赖性降低到一个接口。然后,您的moq回购是
var rep=new Mock()
并且依赖关系变为
私有只读IRepository\u存储库

经典的方法是使用控制反转(这意味着
ServiceManager
不再控制创建
存储库
),通常通过依赖项注入实现(这意味着依赖项
存储库
被“注入”到
服务管理器


你似乎已经知道了,自从你写了

如果可能,我不想创建像新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;
    }
}
只需在应用程序中使用
newservicemanager()
,并在测试中使用
newservicemanager(repositoryMock)


但是,如果您使用IOC容器(例如StructureMap),注入依赖项非常简单:您可以将对象的创建留给IOC容器,并使您的
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;
    }
}