Dot-Net

儲存庫本身通常不經過測試?

  • January 8, 2012

很抱歉,我是儲存庫模式、單元測試和 orm 工具的新手。

我一直在研究單元測試和儲存庫模式,並得出了一些結論,不知道我是否正確。

例如,儲存庫模式有助於在使用它的控制器中替換單元測試,對嗎?因為創建上下文的存根/偽造(在 EF 中)或會話(在 NH 中)更難,對吧?儲存庫本身沒有經過測試?為什麼?

使用帶有儲存庫模式的 EntityFramework 或 NHibernate,如果我想測試我的儲存庫,我需要進行集成測試嗎?因為如果我使用我的上下文/會話的虛假實現,我沒有做真正的測試?因為上下文/會話本身就是儲存庫(我的意思是它們實現了添加、刪除、編輯、GetById、GetAll 等真正的邏輯)?

帶有 EF 或 NH 的儲存庫模式就像一個包裝器?(不僅是包裝器,我知道這是域的導入概念。)

在這種情況下,我會嚴格區分 EF 和 NH,並且我不會將這兩種技術都包含在同一個問題中。簡單的 NH 更成熟,並且具有導致程式碼更容易測試的架構。同樣,在 NH 的情況下,您可以簡單地將數據庫切換到另一個數據庫(如 SQLite),它仍然可以工作,這在 EF 的情況下不必如此,因為切換數據庫可能會導致測試完全不同的應用程序 - 特別是如果您在 MS 和非 MS 數據庫之間切換。

什麼是儲存庫?讓我們看看Martin Fowler 的定義

儲存庫在域和數據映射層之間進行調解,就像記憶體中的域對象集合一樣。客戶端對像以聲明方式構造查詢規範,並將它們送出給 Repository 以獲得滿意。對象可以添加到儲存庫中,也可以從儲存庫中刪除,就像它們可以從簡單的對象集合中一樣,儲存庫封裝的映射程式碼將在幕後執行適當的操作。從概念上講,儲存庫封裝了持久化在數據儲存中的一組對像以及對它們執行的操作,從而提供了持久層的更物件導向的視圖。儲存庫還支持實現域和數據映射層之間的清晰分離和單向依賴的目標。

很好的定義。現在想想目的DbSet

  • 它在記憶體收集中起作用嗎?是的,您可以使用它從數據庫中獲取實體或使用Local屬性來獲取已載入的實體。
  • 客戶端可以以聲明方式查詢規範嗎?是的,它被稱為 linq-to-entities。
  • 可以從集合中添加或刪除對象嗎?是的,它可以。
  • 映射是否封裝?是的。
  • 有乾淨的分離嗎?在邏輯上是的。就 API 而言,沒有,因為暴露IDbSet於領域模型將使領域模型依賴於技術 - EF。有問題嗎?理論上是的,對於純粹主義者來說是的,但在 99% 的情況下,這確實不是問題,因為您需要更改 API 的情況很少見,即使您正確分離了 API,它也總是涉及大的更​​改。

DbSet是一個儲存庫。DbSet直接使用和將其包裝到某個通用儲存庫之間的唯一區別是分離。這導致我以前對類似問題的回答 -使用 EF 4.1 的通用儲存庫有什麼意義

現在,您的應用程序中儲存庫的用途是什麼?我看到了你之前的問題,包括這個BaseRepository在實體框架之上建構的問題。如果您認真地將其作為基礎儲存庫,它將成為您的專門儲存庫的父級,該儲存庫為您的域模型處理聚合根並公開僅與特定公開實體類型相關的專門方法,那麼是的 - 您正在使用儲存庫模式並且您需要它。但是,如果您只是包裝上下文和單個集合併呼叫此儲存庫,那麼您很可能只創建了具有可疑附加值的冗餘層,因為這只是DbSet.

在這種情況下,只有一種情況下您的儲存庫(DbSet包裝器)才有意義:

  • 包裝器永遠不會暴露IQueryable(linq-to-entities)
  • 包裝器永遠不會接受Expression<>並將其在內部傳遞給IQueryalbe(linq-to-entities)

這是唯一可以為您提供完全可模擬儲存庫的場景 => 您的上層可以輕鬆進行單元測試。您不會對儲存庫進行單元測試,也不會模擬儲存庫中使用的上下文。儲存庫包含數據訪問和映射邏輯——儲存庫中唯一合理的測試是集成測試。這種情況有什麼問題?您將失去 LINQ 的全部功能,您將不得不包裝/重新實現一些在 EF 中實現的方法和類型。這種儲存庫與使用儲存過程包裝數據訪問時使用的儲存庫相同。

如果您不遵循這種情況,您的生活會容易得多。您將擁有由 LINQ 定義的查詢,但您將無法對程式碼進行單元測試,因為沒有模擬/偽造仍然會將查詢評估為 linq-to-entities。一旦你模擬DbSet或者IQueryable你將使用 linq-to-object,它是 linq-to-entities 的超集。您可以輕鬆編寫一個查詢,該查詢將通過模擬測試,DbSet但在執行時失敗並使用真實的DbSet. 是有關此問題的更多資訊,這裡是查詢範例,它將通過測試但在執行時失敗。在這種情況下,您必須對在儲存庫頂部使用 linq-to-entities 查詢的所有方法使用集成測試(使用真實數據庫)。

Repository介面屬於領域層。但實現屬於基礎設施或數據訪問層。此實現通常不使用單元測試進行測試。它大量使用 ORM API,因此單獨測試儲存庫非常困難和浪費。此問題並非特定於儲存庫:不要模擬您不擁有的類型。

儲存庫應該使用真正的 ORM 進行集成測試。記憶體數據庫是解決這個問題的一種非常流行的方法。

…因為如果我使用我的上下文/會話的虛假實現,我沒有做真正的測試?

即使你設法做到了(我真的懷疑 NHibernate 的情況),你也會浪費你的時間。會話/上下文介面是你無法控制的,你的測試只會重申你對真實事物如何工作的猜測。

因為上下文/會話本身就是儲存庫?

不,Context/Session 是UnitOfWork模式的實現。它不屬於您的域。這是基礎設施。

帶有 EF 或 NH 的儲存庫模式只是一個包裝器?

儲存庫是重要的域概念,它不僅僅是一個“包裝器”。就像您的應用程序不是數據庫的“包裝器”一樣。我認為 DDD 儲存庫介面定義應該盡可能基於Ubiquitous Language,不應該包含任何 ORM 相關的詞或類型。

引用自:https://stackoverflow.com/questions/7110981