簡體   English   中英

嘲笑一個實體?

[英]Mocking an entity?

我聽說某個地方嘲弄一個實體是個壞事,你應該只模擬服務(即使我們沒有做全面的DDD,但是“sorta”DDD)。

那么,鑒於以下典型故事,您如何為它編寫測試?

  • 如果客戶具有“首選”狀態,則應在發生事件時通知她。

首選狀態取決於其他因素,例如,客戶最近購買了10個小部件,或者他的名字以“A”開頭,等等。無論如何,我們假設我們已經實現了此功能。 我如何為上述故事編寫測試? 具體來說,我對可測試性要求在這種情況下如何影響我的設計感興趣。

  1. 我可以使用一些高級模擬框架(如Isolator),它允許我模擬非虛擬屬性。 可測性與設計之間沒有相關性,沒問題。
  2. 我可以將IsPreferred屬性設置為虛擬並模擬它(實際上是stub)。 不知道為什么,但感覺很臟。 請參閱帖子頂部的問題。 此外,不知道它如何改善我的設計。 2A。 隱藏ICustomer接口后面的實體並模擬它。 完全不酷。
  3. 我可以使它成為一個讀寫屬性,但這將是一個非常糟糕的設計決定。

你是如何處理這些故事的?

我在一些書/博客上讀過類似的東西,建議不要模仿域模型中的實體或對象。 據我記得的消息是不要模擬數據,模擬行為 (我可能在XUnit Test Patterns或GOOS一書中讀過這篇文章)。

就個人而言,我認為如果你的實體需要很多設置,那么模擬它是有效的。 讓我舉個例子,假設你有品牌,產品,價格和StockAvailability。 一個品牌有產品,產品有價格和庫存。 測試類調用Brand.IsAvailable(),它反過來檢查至少有一個產品具有有效價格和庫存(這是相當多的邏輯)。 因此,如果您正在嘗試對CUT進行單元測試,那么測試所有Brand.IsAvailable邏輯遠遠超出范圍,因此模擬該方法是有意義的。

如果設置實體很容易,那么使用實體,例如,如果您有一個用戶並且它有一個名為active的屬性,您可以創建一個用戶並在測試中將該屬性設置為構建虛假用戶的成本和分配該屬性可能與模擬方法調用相同,並且(在我看來)更清晰。

我不是ac#expert,但我讀過Isolator是.net的最佳框架之一,所以我會做你在1上提到的。

我不會在實體中加入過多的邏輯。 他們應該關心自己的狀態,例如。 關心自己領域的一致性。 但他們不應該關心整個系統的一致性。 你設置用戶狀態的“user.AddOrder”的例子太過恕我直言。

如果他們做了所有事情,你也會失去實體的可重用性。 如果您獲得其他要求(例如,數據導入,新類型訂單,新類型規則等其他情況),您的實體模型會受到妨礙,則不夠靈活。

缺乏靈活性出現在單元測試中。 當您在單元測試中隔離類時,它會清楚實際封裝的內容,並且不再可以分離。 如果你遇到問題,你的封裝很可能不是很有用。 因此,單元測試是可重用性的一個很好的證明。

示例(偽代碼,不介意我是否錯過了應用程序的要點,它只是為了顯示邏輯所屬的位置):

class User
{
    AccountState State { get; }
    void MakeTopSeller()
}

class Order
{
    decimal GetTotal();
    User Salesman { get; }
}


class OrderService
{
  void AddOrder()
  {
      // ....
      if (order.GetTotal() > ToSellerAmount)
      {
          order.Salesman.MakeTopSeller();
      }
  }
}

編輯 :如果你仍然認為你的方法是合適的(我的意思是我不能從我所知的方面做出決定),你不需要改變它。 但是,如果您的實體需要另一個實體來設置狀態,並且您在測試中需要該狀態,則需要在測試中執行所有這些操作:創建訂單並將其添加到用戶。

還有另一種方法可以解決問題。 您可以將規則放入單獨的類中,例如。 使用策略模式。 通常很難在實體上設置策略,因為底層數據庫層需要注入它們。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM