如果您想要使用TDD(或任何其他高測試覆蓋率的測試方法)和EF,您必須編寫集成或端到端測試。這裏的問題是,任何模擬上下文或存儲庫的方法都會創建測試,它可以測試您的上層邏輯(使用這些模擬)而不是您的應用程序。
簡單的例子:
讓我們定義通用的存儲庫:
public interface IGenericRepository<TEntity>
{
IQueryable<TEntity> GetQuery();
...
}
並讓寫一些商業方法:
public IEnumerable<MyEntity> DoSomethingImportant()
{
var data = MyEntityRepo.GetQuery().Select((e, i) => e);
...
}
現在,如果你嘲笑的庫中,您將使用的LINQ到 - 對象和你將有一個綠色的測試,但如果你使用Linq-To-Entities運行應用程序,你將會得到一個異常,因爲在L2E中不支持索引的選擇過載。
這是一個簡單的例子,但在查詢和其他常見錯誤中使用方法會發生同樣的情況。此外,這也會影響像Add,Update和Delete這樣的方法,這些方法通常暴露在資源庫上如果你不寫一個模擬真正模擬EF上下文和參照完整性的行爲,你將不會測試你的實現。
故事的另一部分是懶惰加載的問題,單元測試對於嘲笑也很難檢測到。
因此,您還應該引入集成或端到端測試,這些測試將使用真實EF環境L2E與真實數據庫一起工作。順便說一句。需要使用端到端測試才能正確使用TDD。要在ASP.NET MVC中編寫端到端測試,您可以使用WatiN,也可以使用SpecFlow來處理BDD,但這樣做確實會增加很多工作量,但是您將會真正測試應用程序。如果您想了解更多關於TDD的信息,我建議您使用this book(唯一的缺點就是Java中的例子)。
集成測試如果不使用通用存儲庫,並且隱藏了某些不會暴露IQueryable
但直接返回數據的類中的查詢,那麼這種測試是有意義的。
例子:
public interface IMyEntityRepository
{
MyEntity GetById(int id);
MyEntity GetByName(string name);
}
現在你可以只寫集成測試,測試執行這個倉庫的,因爲查詢隱藏在這個類,而不是暴露到上層。但是這種類型的存儲庫在某種程度上被認爲是與存儲過程一起使用的舊實現。這種實現會失去很多ORM特性,或者你將不得不做很多額外的工作 - 例如,添加specification pattern以便能夠在上層定義查詢。
在ASP.NET MVC中,您可以用控制器級別的集成測試部分替換端到端測試。
編輯基於評論:
我不說,你需要的單元測試,集成測試和終端到終端的測試。我說做測試的應用程序需要更多的努力。所需測試的數量和類型取決於應用程序的複雜程度,應用程序的預期未來,其他團隊成員的技能和技能。
小型直接項目可以在沒有測試的情況下創建(好吧,這不是一個好主意,但我們都做到了,並且最終它可以工作),但是一旦項目通過某個閾值,您就會發現引入新功能或維護這個項目非常困難,因爲你永遠不知道它是否會破壞已經發揮作用的東西 - 這就是所謂的迴歸。防止迴歸的最佳防禦措施是一套很好的自動化測試。
- 單元測試可以幫助您測試方法。理想情況下,這種測試應該覆蓋方法中的所有執行路徑。這些測試應該非常簡短並且易於編寫 - 複雜的部分可以是設置依賴關係(嘲諷,僞造,存根)。
- 集成測試可幫助您測試跨多個層的功能,並且通常跨多個進程(應用程序,數據庫)進行測試。你不需要爲他們提供所有的東西,而是更多地選擇他們有用的地方。
- 端到端測試類似於用例/用戶故事/功能驗證。他們應該涵蓋整個流程的要求。
不需要多次測試feture - 如果您知道該功能是在端到端測試中測試的,則無需爲同一代碼編寫集成測試。此外,如果您知道該方法僅具有集成測試所涉及的單一執行路徑,則無需爲其編寫單元測試。 TDD方法的效果要好得多,您可以從一個大測試(端到端或集成)開始,然後深入單元測試。
根據您的開發方法,您不必從頭開始進行多種類型的測試,但隨着應用程序變得越來越複雜,您可以稍後介紹它們。 TDD/BDD是個例外,你甚至在寫單行其他代碼之前,應該至少開始使用端到端和單元測試。
所以你問的是錯誤的問題。問題不是更簡單?問題是最終會對你有什麼幫助,什麼複雜性適合你的應用程序?如果您想要輕鬆地進行單元測試的應用程序和業務邏輯,您應該將EF代碼封裝到可以被模擬的其他類中。但在同一時間,您必須引入其他類型的測試以確保EF代碼正常工作。
我不能說你用什麼辦法將適合你的環境/項目/團隊/等,但我可以從我過去的項目解釋例如:
我工作的項目約5-6個月有兩個的同事。該項目基於ASP.NET MVC 2 + jQuery + EFv4,並且是以增量和迭代的方式開發的。它有很多複雜的業務邏輯和大量複雜的數據庫查詢。我們從通用存儲庫和高代碼覆蓋率開始,使用單元測試+集成測試來驗證映射(插入,刪除,更新和選擇實體的簡單測試)。幾個月後,我們發現我們的方法不起作用。我們有超過1.200個單元測試,代碼覆蓋率約爲60%(這不是很好)以及很多回歸問題。改變EF模型中的任何內容都可能在數週內未觸及的部分引入意想不到的問題。我們發現我們缺少對我們的應用程序邏輯進行的集成測試或端對端測試。關於另一個項目的平行團隊也得出了同樣的結論,並且使用集成測試被認爲是新項目的建議。
你說庫增加了「複雜」到你的應用程序,但我要說他們是最初的'開銷',使測試更容易。嘲笑一些存儲庫比嘲笑整個數據上下文更容易。 – Omar 2011-04-10 03:40:12
是的,但我不想在我目前的情況下開始的開銷。我想快速申請進度。我已經失去了太多時間,沒有任何實際進展。添加存儲庫會帶來像IoC,DI等類似的東西。在我開始查看之前,我將不得不編寫大量的測試。我知道這可能是正確的解決方案,但我不是在尋找「正確的」。我正在尋找簡單的(雖然仍然可測試)的解決方案。 – Damb 2011-04-10 03:46:07