2011-04-12 106 views
6

我正在Java中實現一個模型,它需要對集合進行迭代並經歷多個標識階段,它涉及到循環,while循環等。這是我想要的東西在細粒度級別進行測試,以便我相信它已正確實施。單元測試,靜態和工廠

我已經使用它作爲開始單元測試的機會,因爲它是我認識到有益於我的代碼的東西。自那以後,我一直在閱讀叢書,以加快JUnit和單元測試的速度。

基本上我的問題可以歸結爲兩個相互矛盾的建議件我收到:

1)靜是邪惡的。不要碰靜電。不要測試私人,你可能想要在那裏上課。
2)使用工廠創建允許使用參數進行依賴注入 - 可能允許使用模擬和存根進行隔離。

在我的例子我期待執行沿行的操作:

double height = 223.42; // this was set iterating over a collection of doubles 
//blah 
HeightBounds b = HeightBounds.getHeightBounds(height); 
//more blah 

爲了避免建立什麼將成爲一個非常漫長而複雜的代碼塊,我已經這樣做了,我只能整體測試。通過這種方式,我可以測試公共可訪問對象,以確保系統組件全部正確執行。

常識對我說,靜態工廠沒有錯,而且他們很容易測試,但是我錯過了一些盲目明顯的東西,因爲我正在學習測試驅動設計?

謝謝

+1

你應該單元測試每種測試有意義的方法,這包括靜態方法。 – DwB 2011-04-12 15:17:27

+2

「statics is evil」有可能主要針對靜態_variables_,因爲它們在測試之間保留它們的值,因此如果測試沒有正確重置,可能會導致測試之間的依賴關係。在我看來,不接觸靜態變量的靜態_methods_沒有問題。 – 2011-04-12 15:19:59

+0

問題是我可以在類中作爲靜態方法調用來進行邊界檢查,但它會非常程序化,我不想將它列在公共接口中。我可以在不改變可見性的情況下測試靜態方法的一種方法是擴展類以進行測試並製作方法來調用它們,但是我讀到的所有內容都是「靜態方法是代碼味道」,您應該使用類。鑑於我在嵌入式環境中運行,儘管我更喜歡避免創建對象的想法,而不是完美的OO設計......仍在審議! – Uniqe 2011-04-12 15:26:05

回答

3

靜態工廠類會在類和HeightBounds類之間引入耦合。這可能會使你的課難以測試,例如HeightBounds關閉並在DB中查找信息,或者從Web服務等讀取。

如果你改爲將IHeightBounds實現注入到類中,那麼你可以嘲笑所以你可以測試當你的類的依賴做某些事情時會發生什麼。

例如,如果HeightBounds引發異常會怎麼樣?或返回null?或者你想測試什麼時候返回一個特定的HeightBound?使用界面很容易嘲笑這種行爲,對於靜態工廠來說,由於您製作數據以在課堂上創建理想的結果,因此更加困難。

您仍然只能使用HeightBounds的單個實現,並且能夠獨立測試,但即使沒有真正的實現,您也可以測試上述方法。

我可能會有一個IHeightBoundFactory接口並向類中注入一個實現。

至於測試私處,一般你不想。你想要測試2件事中的一件,或者結果是你所期望的,或者是你所期望的相互作用。

如果你有一個名爲Add方法與一個叫GetAll,那麼你可能想測試,當你調用Add,然後調用GetAll你回來,你添加的一種方法。你不在乎這是如何實現的,而是它的工作原理。這是測試結果。通常在這種情況下,您希望創建返回數據的模擬對象。這似乎是你的情況。

如果您在調用Add時希望記錄正在添加的內容,那麼您需要測試與日誌記錄依賴關係的交互,以便注入模擬依賴關係並驗證當您調用Add時與該類的交互發生了。通常在這種情況下,您希望創建具有預期設置的模擬對象,並驗證是否滿足這些期望。它看起來不是這樣,在你上面描述的情況下是必要的。

+0

不是我想做自己的代表,但你可以,一般來說,在接受答案之前要等待,因爲更多的人可能有機會發表他們的意見,或者將我的觀點拍下來:) – 2011-04-12 15:35:54

+0

好的,謝謝,會按照你的建議做,並等待進一步的反饋,並完成解決其他答案(這也涵蓋了很多好的內容)。 – Uniqe 2011-04-12 15:39:50

+0

我認爲這是答案,因爲你能夠發現我想要達到的目標以及我誤解的概念,然後舉出例子填補空白。謝謝 – Uniqe 2011-04-15 08:12:04

2

靜是邪惡的。不要碰靜電。

這裏的「靜態」可能意味着單身,即全局狀態。這在單元測試中確實很難使用,並且會引入很多細微的問題,所以最好避免它。然而,static成員(字段,方法或內部類)通常不一定是本身的問題。

不要測試私人,你可能需要一個班。

如果你覺得需要測試一個私有方法,這是一個跡象表明你的API沒有足夠精細,並且封裝類可能會嘗試做太多,這是真的。通常你可以確定一些連貫的功能組合,這可以更好地提取到一個單獨的類中。這可以改善您的設計,從而使單元測試更加輕鬆。

1

靜態方法基本上殺死了單元測試。

當你想單元測試你的應用程序的基本思想之一是能夠隔離你的代碼的不同部分。您通常通過爲您的環境佈線模擬對象來實現此目的。如果使用靜態方法,則不能連線任何東西。而且,使用靜態方法隱藏對象之間的依賴關係。

在你最後一段你說你想學習測試驅動設計。如果你在之後編寫你的測試你已經編寫了你的​​代碼,你的測試並沒有真正驅動任何東西。先寫測試。

關於私有方法,您通常會對使用這些私有方法的公共方法進行全面測試,因此無論如何您都要覆蓋它們。如果你有一個非常複雜的私人方法,你想測試(你不應該)只是使用反射來使其可訪問。我寧願打破封裝而不是未經測試的代碼。

Misko Hevery在這個話題上有一個非常的nice post

+0

DistanceBounds本身並不存在 - 我仍然在充分考慮如何測試它們,從而充實了需要什麼對象以及該過程。也許TDD並不是我的意思,但基本上,而不是瀑布式的定義我所有的測試/代碼,我期待寫它們,因爲我一次編寫代碼,方法......當然,測試正在驅動我的設計,但是,也許這不是TDD或任何正式的過程。 – Uniqe 2011-04-12 15:53:17

2

靜態工廠的一個問題是,您無法通過模擬替換工廠(以及某些時候由工廠創建的對象)。 - 這是IOC Containers如此有用的原因之一。

+0

謝謝,IoC容器是一個非常好的關鍵字谷歌,我一直在閱讀本:http://martinfowler.com/articles/injection.html – Uniqe 2011-04-14 10:24:35

0

靜態方法本身並不是邪惡的。看看JDK中有多少人在那裏。靜態方法也需要進行單元測試,所以如果你有任何進行和測試。

所以靜態方法殺死單元測試並不是真的。

但是,如果您只是在單元測試中編寫較少的代碼,那麼這是一個錯誤的路徑,因爲正如其他人所說,您應該更好地使用您的對象使用通常的API - 因爲這是你想測試。

首先編寫測試的完整ACK - 它也將幫助您設計更好的API,正確地削減您的課程。

+1

人們說靜態方法殺死單元測試的原因不是因爲你不能測試靜態方法,而是調用靜態方法的代碼很難單獨測試。在Java的情況下,你必須使用支持字節碼工具的框架(如JMockit)來模擬/僞造/存根/ w/e方法。據我瞭解,這並不理想(儘管我最近才瞭解這種可能性)。 – 2012-11-04 15:27:38

+0

其實我個人不知道有人這麼說,所以不能評論「人說」。對我來說,「殺死單元測試」聽起來像「現在你有靜態方法,你真的很麻煩,不能單元測試」,這顯然不正確(正如我所說的)。誠然,這使得測試更加困難,但並非不可能。有時候靜態方法是有益的。一旦你有他們,你應該測試他們。就像你說的是嘲笑其中一種可能性,我會說很好。其他的是準備國家,以便測試工作 - 我做了不止一次,這絕對有可能。 – 2012-11-14 11:06:05

+0

我認爲你的陳述「所以靜態方法殺死單元測試是不對的。」是對相反的迴應。我評論的原因是因爲我覺得你的答案是「靜態方法可以使用,因爲你也可以測試它們」,我想補充我所理解的缺點:嘲笑它們很困難,因爲它更復雜,也比正常嘲笑。一般來說,你希望你的單元測試是簡單的(所以你可以維護它們)和快速(所以你可以經常運行它們)。 – 2012-11-14 13:40:14