在我的ASP.Net MVC应用程序中,我使用IoC来简化单元测试。我的应用程序的结构是Controller -> Service Class -> Repository
类型的结构。为了做单元测试,我有一个InMemoryRepository
类继承我的IRepository
,而不是去数据库,它使用内部List<T>
成员。当我构建我的单元测试时,我只传递一个内部存储库的实例,而不是我的EF存储库。单元测试时我应该使用模拟对象吗?
我的服务类通过我的存储库类实现的AsQueryable
接口从存储库检索对象,因此允许我在没有服务类的情况下在我的服务类中使用Linq,同时仍然抽象出数据访问层。在实践中,这似乎运作良好。
我看到的问题是,每当我看到单元测试谈到,他们都使用模拟对象,而不是我看到的内部方法。在面值上它是有道理的,因为如果我的InMemoryRepository
失败,不仅我的InMemoryRepository
单元测试失败,但是这个失败也会级联到我的服务类和控制器中。更现实的是,我更关心影响控制器单元测试的服务类中的故障。
我的方法还要求我为每个单元测试做更多的设置,并且随着事情变得更加复杂(例如,我在服务类中实现授权),设置变得更加复杂,因为我必须确保每个单元测试会正确授予它与服务类别,因此该单元测试的主要方面不会失败。我可以清楚地看到模拟对象如何在这方面提供帮助。
但是,我不明白如何解决这个完全与嘲笑,仍然有效的测试。例如,我的一个单元测试是,如果我调用_service.GetDocumentById(5)
,它会从存储库中获取正确的文档。这是一个有效的单元测试的唯一方法(据我了解)是如果我有2或3个文件存储,并且我的GetdocumentById()
方法正确地检索Id为5的那个。
我将如何有一个嘲笑库AsQueryable
调用,以及如何确保我没有掩盖任何问题,我用我的Linq语句硬编码设置模拟存储库时的返回语句?使用InMemoryRepository
保持我的服务类单元测试更好吗,但将控制器单元测试更改为使用模拟服务对象?
编辑: 去在我的结构之后再次我记得是防止控制器单元测试嘲讽的并发症,因为我忘了我的结构比我原来说有点复杂。
A Repository
是一种对象类型的数据存储,所以如果我的文档服务类需要文档实体,它会创建一个IRepository<Document>
。
控制器通过IRepositoryFactory
。 IRepositoryFactory
是一个类,它可以很容易地创建存储库,而无需将存储库直接存入控制器,或让控制器担心哪些服务类需要哪些存储库。我有一个InMemoryRepositoryFactory
,它给出了服务类别InMemoryRepository<Entity>
实例化,并且我的EFRepositoryFactory
也有同样的想法。
在控制器的构造函数中,通过传入传入该控制器的IRepositoryFactory
对象来实例化私有服务类对象。
因此,例如
public class DocumentController : Controller
{
private DocumentService _documentService;
public DocumentController(IRepositoryFactory factory)
{
_documentService = new DocumentService(factory);
}
...
}
我不能看到如何使用这种架构嘲笑我的服务层,使我的控制器单元测试,不融合测试。我可能有一个糟糕的单元测试架构,但我不确定如何更好地解决让我想要首先创建一个存储库工厂的问题。
“使用InMemoryRepository'保持我的服务类单元测试更好,但更改我的控制器单元测试以使用模拟服务对象?”对,就是这样。 – 2010-11-05 14:56:22
我刚刚更新了这个问题,在测试控制器对我来说看起来不太明显的时候,为什么嘲笑服务层更加详细。 – KallDrexx 2010-11-05 15:24:13