在我的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