2009-05-30 59 views
8

這是常見的有與字符串參數的方法,必須驗證agains爲零或爲空,如本實施例中的類:我應該如何在方法中測試空和/或空字符串參數?

public class MyClass { 

    public void MyMethod(string param){ 

     if(string.IsNullOrEmpty(param)){ 
      throw new ArgumentNullException(...); 
     } 
     //... 
    } 
} 

很明顯,該方法的行爲是兩個相同的(無效)值。這是一個非常普遍的情況,當談到測試這些方法時,我總是懷疑如何去做。我總是創建兩個單獨測試了這些情況:

[TestClass] 
public class Tests { 

    [TestMethod] 
    public void MyMethod_should_fail_if_param_is_null(){ 
     //... 
     myclass.MyMethod(null); 
     //... 
    } 

    [TestMethod] 
    public void MyMethod_should_fail_if_param_is_empty(){ 
     //... 
     myclass.MyMethod(""); 
     //... 
    } 

}

但我看到了太多的冗餘。這些測試完全相同,唯一的區別是傳遞給方法的參數。這讓我非常困擾,因爲我必須爲每個字符串參數創建兩個測試。具有3個參數的方法將僅具有6個測試來測試參數。

我認爲這是測試這些參數的正確方法,但是如果我知道99%的字符串參數將以同樣的方式進行驗證,那麼測試它們爲空(或空)並假設它們會更好在另一種情況下的行爲將是相同的?

我想知道你對此有何看法。我知道我問的是技術問題而不是技術問題,但我認爲測試社區可能對這種情況有一些有趣的看法。

謝謝!

回答

11

我個人認爲考慮使用單個測試的所有參數。這不符合單元測試的正常教條,但是它增加了測試的可讀性(通過最小化專用於相當重複的情況的測試代碼量)並且沒有太多的缺點。是的,如果測試失敗,您不知道第一次失敗後的所有檢查是否也會失敗 - 但是真的是在實踐中是否存在問題?

重要的一點是確保你有一個捷徑來測試案例。比如,你可以寫這樣的事情(如果你的單元測試框架,沒有它的話):

public static void ExpectException<T>(Action action) where T : Exception 
{ 
    try 
    { 
     action(); 
     Assert.Fail("Expected exception " + typeof(T).Name); 
    } 
    catch (T exception) 
    { 
     // Expected 
    } 
} 

然後,你可以寫:

[Test] 
public void MyMethodFailsWithInvalidArguments() 
{ 
    ExpectException<ArgumentNullException>(() => myClass.MyMethod(null)); 
    ExpectException<ArgumentException>(() => myClass.MyMethod("")); 
} 

不是做每一個與更簡潔一個單獨的try/catch塊,或者甚至使用一個ExpectedException屬性和多個測試。

如果您還想驗證在每種情況下都沒有觸摸過模擬對象(以檢查是否可以避免副作用),或者可能會重載常見的例外(如ArgumentNullException),您可能需要重載。

對於單參數的方法,你甚至可以寫一個方法來封裝你所需要的東西:

public void ExpectExceptionForNullAndEmptyStrings(Action<string> action) 
{ 
    ExpectException<ArgumentNullException>(() => action(null)); 
    ExpectException<ArgumentException>(() => action("")); 
} 

然後調用它:

[Test] 
public void MyMethodFailsWithInvalidArguments() 
{ 
    // This *might* work without the 
    ExpectExceptionForNullAndEmptyStrings(myClass.MyMethod); 
} 

...也許再一個方法只有一個參數,但是一個非空的返回類型。

這可能會有點遠,雖然:)

+0

謝謝你的快速反應! 我已經創建了我自己的ExpectException版本(你可以在這裏查看http://gerardocontijoch.wordpress.com/2008/12/02/uso-de-expectedexceptionattribute-para-testear-excepciones/),並使用它在這些情況下。不能沒有它:P 我喜歡你提出的解決方案,我想過,但正如你所說,「這不符合單元測試的正常教條」,我只想跟隨它,你知道,習慣良好的做法。畢竟,我可能會選擇這個解決方案。讓我們來看看還有什麼其他的想法... – 2009-05-30 21:49:17

+1

事情是,我不相信遵循教條,把實用主義推出窗外*是一個很好的習慣:)這是值得的*知道*的教條,但隨後有意識地忽略它對於特定的情況,我們已經權衡了利弊,並發現它不起作用。 – 2009-05-30 22:15:01

-2

如果您使用Java和JUnit你可以使用這個語法

@Test(expected = IllegalArgumentException.class) 
public void ArgumentTest() { 
    myClass.MyMethod(""); 
    myClass.MyMethod(null); 
} 
相關問題