2010-02-06 72 views
2

我們最近採用了用於驗證域對象的規範模式,並且現在要引入我們的域對象的單元測試以提高代碼質量。規範模式單元測試

我發現的一個問題是如何最好地單元測試下面示例中顯示的驗證功能。規範命中數據庫,所以我想能夠嘲笑它,但因爲它是在線實例化我不能這樣做。我可以處理接口,但這會增加代碼的複雜性,因爲我們可能有很多規範,我們最終會有很多接口(請記住,我們正在引入單元測試,並且不想給任何人一個藉口來拍攝它下)。

鑑於此場景,我們如何最好地解決單元測試我們的域對象中的規範模式的問題?

... 
public void Validate() 
{ 
    if(DuplicateUsername()) 
    { throw new ValidationException(); } 
} 

public bool DuplicateUsername() 
{ 
    var spec = new DuplicateUsernameSpecification(); 
    return spec.IsSatisfiedBy(this); 
} 

回答

5

一個更溫柔的引入接縫可以通過製作核心方法virtual來實現。這意味着你可以使用Extract和Override技術進行單元測試。

在綠地開發中,我發現這種技術不是最理想的,因爲有更好的替代方案可用,但它是將可測試性改裝爲已有代碼的好方法。

作爲一個例子,你寫了你的規範命中數據庫。在該實現中,您可以將該規範的那部分提取到Factory Method,然後您可以在單元測試中覆蓋該部分。

一般而言,書Working Effectively with Legacy Code提供了有關如何使代碼可測試的很有價值的指導。

+0

感謝您的反饋Mark,我同意你所說的一切,但希望有一個體面的解決方案。有些東西在測試項目中繼承類和重寫方法方面不太合適,我認爲如果我們首先想出了一個體面的設計,那麼我們可以避免這種開銷,這正是我希望的離開這篇文章。 – Burt 2010-02-06 22:15:36

+1

@Burt:那麼我可能誤解了你的問題。 '體面'設計圍繞SOLID進行。特別是開放/關閉原則對可測試性非常重要。這又涉及DI,這意味着大量的界面和抽象工廠,並且我讀了你的問題,說明你現在無法真正負擔這個稅。 – 2010-02-06 22:48:47

+0

我並不想過度搖擺船,但它像接口一樣是最好的方式來實現我想要的。 – Burt 2010-02-06 23:49:55

1

您可以提取getDuplicateUsernameSpecification()到它自己的公共方法,那麼子類並覆蓋你的測試。

+0

這是一個好主意,我們正在考慮覆蓋域對象並覆蓋DuplicateUsername方法,但它不適合我。 – Burt 2010-02-06 22:05:53

1

如果你使用的IoC,那麼你可以解決DuplicateUsernameSpecification和測試模型的處理最後一個

編輯:我們的想法是,以取代工廠方法直接構造函數的調用。事情是這樣的:

public bool DuplicateUsername() 
{ 
    var spec = MyIocContainer.Resolve<DuplicateUsernameSpecification>(); 
    return spec.IsSatisfiedBy(this); 
} 
+1

將IoC容器用作服務定位器通常不被視爲最佳實踐。使用構造函數注入更好。你仍然可以使用一個容器,但只需要在你的應用程序的一個地方浮現(或耦合)一個地方。 – TrueWill 2010-02-06 22:44:48

+0

我想過這個,並試圖實現它,我可以模擬一個具體的類沒有使用嘲笑框架,即最小起訂量的接口? – Burt 2010-02-06 23:00:48

+1

我認爲不可能嘲諷一種不是虛擬的方法,所以如果通用化可能用於接口如ISpecification {bool IsSatisfiedBy (T target); }可以工作。 – 2010-02-06 23:07:35

2

,如果你不想做一個工廠的構造函數注入,使規範mockable ......你有沒有考慮TypeMock?處理這類事情非常強大。你可以告訴它模擬將要創建的X類型的下一個對象,它可以模擬任何東西,不需要虛擬等。