2013-08-26 32 views
2

考慮以下方法負面測試 - 我應該期待確切的例外嗎?

public void Foo(string str) 
{ 
    if (str == null) 
     throw new ArgumentNullException("str"); 

    if (str.Length != 5) 
     throw new MyException(); 
} 

假設我想爲它編寫像這樣一個負測試:

public void TestFoo() 
{ 
    try 
    { 
     Foo(null); //this could be an remote call (e.g. WCF) 
     Assert.Fail("Expected ArgumentNullException"); 
    } 
    catch (ArgumentNullException) {} //should this be "Exception" instead? 

    try 
    { 
     Foo("four"); //this could be an remote call (e.g. WCF) 
     Assert.Fail("Expected MyException"); 
    } 
    catch (MyException) {} //should this be "Exception" instead? 
} 

在我看來,那醒目如上一個特定的異常是一個實現細節,這可能使測試變得脆弱並且與實現(而不是接口)耦合。顯然MyException可能會改變一天,但即使是ArgumentNullException也可能被封裝在一些其他異常(例如未來的WCF行爲)中。通常,測試知道「四個」應該失敗,而這就是所關心的 - 失敗。

例外情況(沒有雙關語意)或許應該在異常被轉換成被傳遞給用戶的東西的情況下,如用戶友好的信息(例如,它被映射到用戶名已經採取UserNameTakenException ,嘗試不同的一個)。在這種情況下,您需要確保傳達正確的錯誤。即使這樣,它也有點問題,因爲它意味着每種可能的用戶錯誤都會有不同類型的異常,但這可能不會太糟糕(通常不會太多)。

我的思路是否有意義?我是否應該在不涉及面向用戶的異常的測試用例中捕獲通用的Exception

+1

你不會在TestFoo中捕獲異常。您將該方法歸入預期的例外。 – phillip

+2

您可能會因爲基於觀點而大吃一驚,但在我看來它非常有意義 - 在特定情況下拋出的異常是方法調用/ API的合同的一部分,因此應該通過測試來保護。 –

+0

我想這取決於測試框架,雖然...如:Assert.Throws (()=> wmd.DoItNow()); – phillip

回答

3

簡單地寫至少4次測試:

[Test] 
[ExpectedException(typeof(ArgumentNullException))] 
public void TestFooForNull() 
{ 
    Foo(null); 
} 


[Test] 
[ExpectedException(typeof(MyException))] 
public void TestFooForInvalidSizeTooShort() 
{ 
    Foo("1234"); 
} 


[Test] 
[ExpectedException(typeof(MyException))] 
public void TestFooForInvalidSizeTooLong() 
{ 
    Foo("123456"); 
} 


[Test] 
public void TestFoo() 
{ 
    Foo("12345"); 
} 

當編寫單元測試,這是最好的治療每次測試一個特定的情況下。

+2

羅伊,感謝你的回答,分離可能是更好的選擇,但這不是問題。儘管我收集到了您的代碼,但您仍支持這樣的觀點:應該預期確切的例外情況,這與收到的其他答覆是內聯的。 –

0
> should I expect the exact exception? 
    > ... 
    > Should I indeed catch the generic Exception in test cases that 
    > don't involve user-facing exceptions ? 

在dotnet中,捕獲通用的Exception並不是一個好主意,因爲它也會捕獲AssertionException。我認爲它也與java一樣

public void ThisTestWillNeverFail() 
{ 
    try 
    { 
     Assert.Fail("some error message"); 
    } 
    catch (Exception) 
    { 
    } 
}