我有一项服务,我想要测试而不使用"真正的"存储库,但是一个模拟存储库。 主程序
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来保存模拟。 这是一般采用的最佳解决方案吗?
答案 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
,然后将ServiceManager
与Repository
的依赖关系减少到接口。您的moq仓库为var rep = new Mock<IRepository>();
,依赖关系变为private readonly IRepository _repository;
。