2016-09-09 199 views
1

我必須處理沒有測試的遺留應用程序。所以在我開始重構之前,我想確保一切都按照原樣進行。AnyString()作爲單元測試的參數

現在想象一下以下情況:

public SomeObject doSomething(final OtherObject x, final String something) { 
    if(x == null) throw new RuntimeException("x may not be null!"); 
    ... 
} 

現在我想測試空檢查,所以可以肯定它的工作原理,我不失去它,一旦我重構。

所以我做了這個

@Test(expected = RuntimeException.class) 
public void ifOtherObjectIsNullExpectRuntimeException() { 
    myTestObject.doSomething(null, "testString"); 
} 

現在,這個工作當然。

但不是「testString」我想傳入一個隨機字符串。

所以我試着用:

但是,這是不允許的,因爲我得到

org.mockito.exceptions.misusing.InvalidUseOfMatchersException: ......你無法使用驗證之外的說法匹配器或stubbing

我明白這個意思,但我想知道我是否仍然可以設法做我想做的事情,而不用參數化我的測試或類似的東西。 我可能會使用的唯一庫是Junit,AssertJ,Mockito和Powermock。

任何想法?

回答

1

好吧,就像Mockito試圖通過這個例外來告訴你,那不是真的如何使用anyString。這些方法只能用於嘲笑。

那麼,爲什麼不試試用一個實際的隨機字符串?我個人最喜歡的場景是:java.util.UUID.randomUUID().toString()。這實際上總是會產生一種從未用於以前測試的全新字符串。

我還想補充一點,如果你正在爲你的SomeObject課寫作測試,你應該避免嘲笑SomeObject的行爲。從你的例子來看,你並不完全是這樣做的,但看起來你可能正在走這條路。模擬您正在測試的實現的依賴關係,而不是實現本身!這個非常重要;否則你實際上沒有測試任何東西。

+0

這適用於字符串,但例如長褲或其他物體? – Sorona

+0

另外,randomUUID()永遠不會返回null afaik,所以這是一個主要缺點。 – Sorona

+0

@Sorona請參閱[java.util.Random](https://docs.oracle.com/javase/7/docs/api/java/util/Random.html)。您可以在那裏找到用隨機值進行測試所需的一切。另外,如果你想專門測試一個空值,那應該是一個單獨的單元測試。單元測試應該便宜且快速;不要害怕在你認爲有必要的地方添加新的測試用例! – nasukkin

1

那麼我沒有太多的mockito知識,但你總是可以創建自己的隨機字符串生成器。也許可以工作,你可以修改更多類型的輸入

2

測試應該是確定性的。在測試中使用隨機值會在調試失敗的測試時難以重現行爲。我建議你爲測試創建一個String常數,例如"abcdefg"

+0

我同意許多測試應該是確定性的,但是存在參數化測試存在的原因。你並不總是想要做TDD,但是BDD也是這樣,測試套件會嘗試各種可能的(和「不可能的」)值,只是爲了看你的測試失敗。我個人看到兩種觀點的好處。如果你只進行確定性測試,就像在「測試程序員所考慮的測試」中那樣,即使是最基本的真實世界場景,你也不能總是能夠覆蓋。 – Sorona

+1

@Sorona參數化測試當然可以是確定性的。 –

+0

他們可以,但是,他們並不總是。那麼,實際上,如果你在計算機科學中圍繞框架和隨機性,他們可能總是「確定性」;)但是,我在這裏要做的是確保不管第二個參數如何,它總是會失敗。因此,我想提高我的機會,如果某個對象出現,它不會破壞我的實現。測試將基本上全天候運行,所以統計... – Sorona

2

你在這裏混淆了概念。

所有這些「嘲笑」像anyString助手()是指配置模擬對象時使用。

但是當你檢查你的測試代碼:

@Test(expected = RuntimeException.class) 
public void ifOtherObjectIsNullExpectRuntimeException() { 
    myTestObject.doSomething(null, "testString"); 
} 

,你會發現:絕對不會有嘲諷參與本次測試。你只需不能在那個地方使用那些Mokito電話;因爲那個地方「沒有Mokito」。

而只是爲了記錄 - 無論如何不需要在這裏過高。你的邏輯在這裏非常清楚:當第一個參數爲空時,你拋出異常。因此,作爲第二個參數來說,它根本不重要。所以想想一個小時如何用任何第二個論證來測試null,在我眼裏是:浪費你的時間。

最後提示:有的java.lang.Objects 而那類具有零一個很好的檢驗,所以我的生產代碼只是看起來像

public SomeObject doSomething(final OtherObject x, final String something) { 
    Objects.requireNonNull(otherObject, "otherObject must not be null"); 
    Objects.requireNonNull(something, "something must not be null"); 

唯一的區別有:要求...拋出NullPointerExceptions

最後終於:有人建議對每個參數進行最終處理;但我不會那樣做。它在所有病例的99%中增加了沒有值。這意味着你有更多的代碼可以閱讀;沒有很好的理由。但這是一個風格問題。

編輯關於具有測試,以檢查爲未來的潛在變化註釋:你不應該這樣做:

  1. 在一定程度上,你的輸入是如何驗證是一個實現細節。您不測試實現細節。換句話說:
  2. 你的方法有一個特定的合約(例如,你通過編寫一個javadoc來非正式地指定「在空輸入時拋出NPE」)。您的測試應該確認恰好爲表示當前合同。合約是:如果第一個參數爲空則拋出。

也許是另一種觀點;因爲我仍然認爲你在這裏浪費你的時間!您應確保所有界面清晰,易於理解且易於使用。他們允許你的代碼的用戶輕鬆地做正確的事情;並防止他做錯事。這就是你應該關注的 - 整體界面的質量! 因此,不要擔心如何爲潛在的未來變化編寫測試;只要確保你的代碼庫基本一致。

+0

事情是,我同意你的看法。但是真的發生了,人們改變了代碼,以便拋出異常'if(a &&!b)'而不是'if(a)'...我想要一種測試方法來確保只有該檢查使用第一個參數。 – Sorona

相關問題