ASP.NET MVC3 和實體框架程式碼優先架構
我之前的問題讓我重新思考了層、儲存庫、依賴注入和這樣的架構東西。
我的架構現在看起來像這樣:
我首先使用 EF 程式碼,所以我只創建了 POCO 類和上下文。這會創建數據庫和模型。
更高級別是業務層類(提供者)。我為每個域使用不同的提供程序…例如 MemberProvider、RoleProvider、TaskProvider 等,並且我在每個提供程序中創建我的 DbContext 的新實例。
然後我在我的控制器中實例化這些提供程序,獲取數據並將它們發送到視圖。
我最初的體系結構包括儲存庫,我把它去掉了,因為我被告知它只會增加複雜性,所以我為什麼不只使用 EF。我想這樣做.. 直接從控制器使用 EF,但我必須編寫測試,而且它與真實數據庫有點複雜。我不得不以某種方式偽造 - 模擬數據。所以我為每個提供者製作了一個介面,並在列表中製作了帶有硬編碼數據的假提供者。有了這個,我又回到了一些我不確定如何正確進行的地方。
這些事情很快就開始變得過於復雜……許多方法和“模式”……它會產生太多的噪音和無用的程式碼。
是否有任何簡單且可測試的體系結構用於使用實體框架創建 ASP.NET MVC3 應用程序?
如果您想同時使用 TDD(或任何其他具有高測試覆蓋率的測試方法)和 EF,您必須編寫集成或端到端測試。這裡的問題是,任何模擬上下文或儲存庫的方法都只會創建可以測試您的上層邏輯(使用這些模擬)而不是您的應用程序的測試。
簡單的例子:
讓我們定義通用儲存庫:
public interface IGenericRepository<TEntity> { IQueryable<TEntity> GetQuery(); ... }讓我們寫一些業務方法:
public IEnumerable<MyEntity> DoSomethingImportant() { var data = MyEntityRepo.GetQuery().Select((e, i) => e); ... }現在,如果您模擬儲存庫,您將使用 Linq-To-Objects 並且您將獲得綠色測試,但如果您使用 Linq-To-Entities 執行應用程序,您將收到異常,因為 L2E 不支持使用索引選擇重載。
這是一個簡單的例子,但在查詢中使用方法和其他常見錯誤也會發生同樣的情況。此外,這也會影響通常在儲存庫中公開的添加、更新、刪除等方法。如果您不編寫將精確模擬 EF 上下文行為和引用完整性的模擬,您將不會測試您的實現。
故事的另一部分是延遲載入的問題,通過針對模擬的單元測試也很難檢測到這些問題。
因此,您還應該引入集成或端到端測試,這些測試將使用真實的 EF 上下文和 L2E 對真實數據庫起作用。順便提一句。需要使用端到端測試才能正確使用 TDD。要在 ASP.NET MVC 中編寫端到端測試,您可以使用 WatiN,也可以使用SpecFlow for BDD,但這確實會增加很多工作,但您將真正測試您的應用程序。如果您想了解更多關於 TDD 的資訊,我推薦這本書(唯一的缺點是範例是用 Java 編寫的)。
IQueryable如果您不使用通用儲存庫並且將查詢隱藏在某個不會公開但直接返回數據的類中,則集成測試是有意義的。例子:
public interface IMyEntityRepository { MyEntity GetById(int id); MyEntity GetByName(string name); }現在您可以編寫集成測試來測試此儲存庫的實現,因為查詢隱藏在此類中並且不會暴露給上層。但是這種類型的儲存庫在某種程度上被認為是與儲存過程一起使用的舊實現。使用此實現,您將失去很多 ORM 功能,或者您將不得不做很多額外的工作 - 例如添加規範模式以便能夠在上層定義查詢。
在 ASP.NET MVC 中,您可以使用控制器級別的集成測試部分替換端到端測試。
根據評論編輯:
我並不是說你需要單元測試、集成測試和端到端測試。我說製作經過測試的應用程序需要更多的努力。所需測試的數量和類型取決於您的應用程序的複雜性、應用程序的預期未來、您的技能和其他團隊成員的技能。
可以在根本沒有測試的情況下創建小型直接項目(好吧,這不是一個好主意,但我們都這樣做了,最後它工作了)但是一旦項目通過了一些門檻,你會發現引入新功能或維護項目是非常困難,因為你永遠不確定它是否會破壞已經起作用的東西——這就是所謂的回歸。對回歸的最佳防禦是一套好的自動化測試。
- 單元測試可幫助您測試方法。理想情況下,此類測試應涵蓋方法中的所有執行路徑。這些測試應該非常簡短且易於編寫 - 複雜的部分可以是設置依賴項(模擬,faktes,存根)。
- 集成測試可幫助您跨多個層測試功能,通常跨多個程序(應用程序、數據庫)。您不需要為所有事情都擁有它們,更多的是經驗來選擇它們有幫助的地方。
- 端到端測試類似於案例/使用者故事/功能的驗證。它們應該涵蓋整個需求流程。
不需要多次測試一個功能 - 如果您知道該功能是在端到端測試中測試的,您就不需要為相同的程式碼編寫集成測試。此外,如果您知道該方法只有集成測試涵蓋的單一執行路徑,則無需為它編寫單元測試。這在 TDD 方法中效果更好,您從大型測試(端到端或集成)開始並深入到單元測試。
根據您的開發方法,您不必從一開始就使用多種類型的測試,但您可以稍後再介紹它們,因為您的應用程序將變得更加複雜。TDD/BDD 是個例外,在您編寫單行其他程式碼之前,您應該至少開始使用端到端測試和單元測試。
所以你問錯問題了。問題不是什麼更簡單?問題是最終什麼會對您有所幫助,什麼複雜性適合您的應用程序?如果您想輕鬆地對應用程序和業務邏輯進行單元測試,您應該將 EF 程式碼包裝到其他一些可以模擬的類中。但同時您必須引入其他類型的測試以確保 EF 程式碼正常工作。
我不能說你哪種方法適合你的環境/項目/團隊/等等。但我可以解釋一下我過去項目的例子:
我和兩位同事在這個項目上工作了大約 5-6 個月。該項目基於 ASP.NET MVC 2 + jQuery + EFv4 並以增量和迭代的方式開發。它有很多複雜的業務邏輯和很多複雜的數據庫查詢。我們從通用儲存庫和高程式碼覆蓋率開始,通過單元測試+集成測試來驗證映射(用於插入、刪除、更新和選擇實體的簡單測試)。幾個月後,我們發現我們的方法不起作用。我們有超過 1200 個單元測試,程式碼覆蓋率大約 60%(這不是很好)和很多回歸問題。更改 EF 模型中的任何內容都可能在數週未觸及的部分中引入意外問題。我們發現我們缺少應用程序邏輯的集成測試或端到端測試。