2008-11-24 182 views
10

我理解需要測試具有邏輯的類(例如可以計算折扣的類),您可以在其中測試實際的類。我爲什麼要寫一個假類和單元測試呢?

但是我剛開始爲一個充當存儲庫的項目編寫單元測試(從數據庫獲取對象)。我發現自己正在編寫一個實現了ISomethingRepository接口的'假'存儲庫。它在內部使用Dictionary<Guid, Something>進行存儲。它實現接口的Add(Something)GetById(Guid)方法。

我爲什麼要寫這個?我正在編寫的東西實際上會在軟件部署時使用,對吧?我真的不明白這個練習的價值。

我也得到了使用模擬對象的建議,我可以提前設置以滿足某些期望。這對我來說似乎更加毫無意義:當然,測試會成功,我已經嘲笑/僞裝成功!而且我還不能確定實際的軟件會連接到數據庫時,它應該執行...

迷茫...

有人點我在正確的方向,以幫助我理解這?

謝謝!

+0

我對此表示滿意,因爲這經常令我感到厭煩。大多數快速的TDD倡導者傾向於意外陷入這種情況,最終導致測試場景/代碼在現實中不會發生。 – FlySwat 2009-08-30 22:57:38

回答

13

你不是在測試你的模擬對象,而是在與它進行交互的其他類。所以你可以舉個例子來測試一個控制器是否將一個保存方法調用轉發到你的虛擬倉庫。如果您正在「測試您的假物品」,則出現問題

+1

是的,這就是我的想法。那麼我對測試我的數據訪問代碼有錯誤的想法。 例如:http://tinyurl.com/6qojvh – 2008-11-24 14:54:04

0

因爲您想以簡單的方式測試實現而不測試實際的具體類,所以您編寫了稱爲Stub或Mock對象的「假」類。目的是通過僅測試接口(或抽象類)來簡化測試。

在你的例子中,你正在測試的東西有一個詞典。它可能會被數據庫真實填滿,或者有很多邏輯背後的邏輯。在你的「假」對象中,你可以通過使所有的數據保持不變來簡化所有的事情。這樣您只測試接口的行爲,而不測試具體對象的構建方式。

+0

我明白了,但那有價值嗎?我寫了*假*並進行了測試。它不用於任何地方的生產代碼。那麼爲什麼寫它並測試它呢? – 2008-11-24 14:51:20

+1

測試你的實現,而不必在你的路徑中包含具體元素。您可以取出大量代碼並專注於您的測試目的。我在我的帖子中的例子很好......數據庫之一......你不需要有一個「真正的數據庫」,你可以僞造它...... – 2008-11-24 15:00:59

2

模擬/存根對象的目的不是要測試,而不是你想測試單元的,它允許您測試單元,而無需其他類。

它基本上是這樣的,你可以一次測試一個類,而不必測試他們也依賴的所有類。

+0

是的,這就是我的想法。因此,在通常使用存儲庫代碼的「更高層」中,我可以注入一個模擬測試,以便它實際上不會連接到數據庫,對嗎? – 2008-11-24 14:53:07

+2

對那個 – 2008-11-24 14:53:32

1

誰在監視觀察者?

有趣的是,如果模擬實現爲角落案例拋出特定的異常,那麼您知道使用或依賴IRepositorySomething的類可以處理在現實生活中拋出的異常。使用測試數據庫無法輕鬆生成這些異常中的一些。

您不用單元測試來測試Mock對象,但可以使用它來測試依賴它的類。

3

不要測試模擬類。使用模擬類來測試生產類。

測試支持類的整點是要有一些可以預測其行爲的東西。如果您需要測試測試支持類以預測其行爲,則存在問題。

在您評論中鏈接的假數據庫文章中,作者需要單元測試他的假數據庫,因爲它是他的產品(至少在文章的上下文中)。

編輯:更新的條款要更一致。

  • 模擬 - 以嘲弄的框架
  • 假創造 - 手動創建,實際上可能會發揮一些。
  • 測試支持 - 嘲笑,假貨,存根,以及所有其他。不生產。
1

你不應該測試模擬類。

通常你會做的是:你爲所測試的類與所有類進行交互的類創建模擬類。

假設您正在測試一個名爲Bicycle的類,該類需要類Wheel,Saddle,HandleBar等的構造函數對象。

然後在課堂上你要測試自己的方法GetWeight這可能遍歷每個部分並調用屬性/方法權重,然後返回總數。

你做什麼:

  • 你寫一個模擬類簡單地​​ 實現了權重比特
  • 然後你通過這些模擬類的自行車
  • 每個部分 (輪,馬鞍等)
  • 測試GetWeight方法上的自行車類

這種方式,你在f在測試GetWeight的自行車類的方式,是獨立於其他類OCUS(說,他們還沒有實現,不確定性等)

1

而是自己寫一個假類的,你可以使用一個工具(如犀牛或Typemock)來嘲笑它。這比自己寫所有的嘲諷要容易得多。就像其他人說的那樣,沒有必要測試假代碼,如果您使用該工具,則不需要代碼。

1

實際上我發現了兩個用於存儲庫實現測試的模擬類。

第一個是測試使用您提到的「ISomethingRepository」等價物的實現的服務。但是,我們的存儲庫實現是由工廠創建的。這意味着我們會針對「ISomethingRepository」編寫測試,但不直接針對「MockSomethingRepository」。通過對接口進行測試,我們可以輕鬆斷言,我們測試的代碼覆蓋率覆蓋了接口的100%。代碼評審提供了簡單的驗證,即新界面成員已經過測試即使開發人員針對工廠返回的模擬運行,構建服務器也具有不同的配置,用於測試工廠在每晚構建中返回的具體實現。它在測試覆蓋率和本地性能方面提供了兩全其美。

第二個使用是我很驚訝,沒有人提到過的一個。我的團隊負責中間層。我們的Web開發人員負責Web產品的前端。通過構建模擬存儲庫實現,在開始前端工作之前沒有等待數據庫建模和實施的人爲障礙。可以編寫視圖來構建模擬,以提供最少量的「真實」數據以滿足Web開發人員的期望。例如,可以提供數據以包含最小和最大長度的字符串數據,以驗證這些數據不會中斷它們的實現等。

由於我們使用的工廠連接到要返回的「ISomethingRepository」,因此我們有本地測試配置,構建測試配置,生產配置等。我們故意設法確保項目中沒有任何團隊由於另一個團隊的實施時間而有不合理的等待時間。最大的等待時間仍然由開發團隊提供,但我們能夠以比前端開發更快的速度發掘我們的域對象,存儲庫和服務。

當然,YMMV。 ;-)

0

看一看下面這篇文章就是一個很好的解釋:

http://msdn.microsoft.com/en-us/magazine/cc163358.aspx

基本上,如果你寫一個假的對象,它原來是相當複雜的,有時值得單元測試假貨以確保它按預期工作。

由於存儲庫可能很複雜,因此爲它編寫單元測試通常是有意義的。

0

通常不需要在數據訪問層中運行傳統的單元測試。 也許您可以使用單元測試框架的功能爲您的數據訪問類(即集成測試(=將數據訪問層代碼與數據庫集成))編寫整合樣式單元測試。

例如,在Spring項目中,您可以使用Spring Testcontext在單元測試中啓動Spring上下文,然後連接到真實數據庫並測試查詢返回正確結果。您可能需要自己的數據庫進行單元測試,或者您可以將它們與開發人員數據庫連接起來。

相關問題