2009-11-21 40 views
1

我來到了十字路口。我最近寫了一個沒有TDD的10,000行應用程序(我知道一個錯誤)。我肯定遇到了很多錯誤,但現在我想改造這個項目。這是我碰到的問題。讓我們,做除法函數的例子:TDD如何處理異常和參數驗證?

public int divide (int var1, int var2){ 
if (var1 == 0 || var2 == 0) 
    throw new RuntimeException("One of the parameters is zero"); 
return var1/var2; 
} 

在這種情況下,我拋出一個運行時錯誤,這樣我可以失敗,並至少找到我的代碼被打破了地方。問題是2倍。首先,我在這裏正確使用例外情況嗎?其次,我如何編寫一個測試來處理這個異常?很顯然,我希望它能通過測試,但在這種情況下,它會拋出異常。 不太確定如何解決這個問題。 TDD通常使用不同的方式處理這種情況嗎?

感謝

+1

拋出:IllegalArgumentException(或等價的,如果不是Java)應當被用來代替普通的RuntimeException。 – 2009-11-21 18:14:54

+4

您不能將TDD改裝爲現有的代碼。您可以針對現有代碼編寫單元測試,但那不是TDD。 TDD是一個**設計**過程,您可以先寫**測試**。我會建議爲現有代碼的關鍵公共接口編寫單元測試,並在添加新的類或方法時考慮使用TDD。 – TrueWill 2009-11-21 18:33:45

回答

6

要回答你的第一個問題:

如果它很可能將分母參數divide將是0,那麼你不應該使用異常處理捕獲錯誤來。異常是昂貴的,不應該用來控制程序流程。所以你應該檢查一下,但是返回一個錯誤代碼(或者使用一個可爲空的類型作爲返回值),你的調用代碼應該檢查並適當地處理它。

public int? divide (int var1, int var2) 
{ 
    if (var2 == 0) 
    { 
     return null; // Calling method must check for this 
    } 
    return var1/var2; 
} 

如果零確實是例外 - 例如,應該沒有辦法讓他們通過 - 然後像現在這樣做。

要回答你的第二個問題:

在您的測試方法是檢查你需要一個異常處理故障代碼:

try 
{ 
    divide (1, 0); 
    // If it gets here the test failed 
} 
catch (RuntimeException ex) 
{ 
    // If it gets here the test passed 
} 
+0

嗯好的答案,謝謝。與問題1相關,在發送之前讓調用函數驗證輸入總是更好嗎?無論如何,這可能是必要的。嗯...... – 2009-11-21 17:06:01

+0

@John - 最好把所有的驗證放在同一個地方,這樣如果你的需求改變了,或者你現在可以處理新的輸入,你只需要在一個地方修改代碼,而不是在任何地方都可以修改代碼。叫做。 – ChrisF 2009-11-21 17:09:13

+0

@Chris嗯沒關係。我認爲這是一項艱難的工作,我需要對如何實現這一目標進行一些研究。雖然偉大的一點。感謝您的幫助 – 2009-11-21 17:21:29

8

首先,你的第一個參數(分子)爲零或許不該」不會引發異常。答案應該是零。當用戶嘗試除以零時僅引發異常。其次,有兩種方法(使用JUnit)來測試在應該出現異常時拋出異常。第一個「經典」的方法:

@Test 
public void testForExpectedExceptionWithTryCatch() 
     throws Exception { 
    try { 
     divide (1, 0); 
     fail("division by zero should throw an exception!"); 
    } catch (RuntimeException expected) { 
     // this is exactly what you expect so 
     // just ignore it and let the test pass 
    } 
} 

JUnit 4中較新的方法使用註釋以減少代碼量,你需要寫:

@Test(expected = RuntimeException.class) 
public void testForExpectedExceptionWithAnnotation() 
     throws Exception { 
    divide (1, 0); 
} 

在這裏,因爲我們添加(expected = RuntimeException.class)到註釋,如果調用divide並不擲一個RuntimeException測試將失敗。

+0

第二個例子(JUnit4)簡潔並且效果很好。謝謝。 – 030 2014-06-13 18:35:58

0

我不回答你的主要問題。

我建議使用ArgumentException而不是RuntimeException

編輯:我假設.NET :)

+0

我甚至會建議DivideByZeroException :) – Mathias 2009-11-22 23:53:50

0

你的問題是語言無關的,所以我的回答可能不適用,但在NUnit的.NET(我相信JUnit的太)有用於測試異常的特定符號。在NUnit的,你的測試應該是這樣的:如果異常的正確類型的執行過程中沒有拋出

[Test] 
[ExpectedException(typeof(RuntimeException))] 
public void DivideByZeroShouldThrow() 
{ 
    divide(1,0); 
} 

測試將失敗。
try/catch方法也起作用,並且有其優點(您可以精確地指出您期望發生異常的位置),但最終可能會寫入非常繁瑣。

0

第一個問題由ChrisF和Bill蜥蜴回答得很好。 我只想添加異常測試的替代方案,使用C++ 11,您可以在測試中直接使用lambda。

Assert::ExpectException<std::invalid_argument>([] { return divide(1,0); }, "Division by zero should throw an exception."); 

這相當於:

try 
{ 
divide(1,0); 
Assert::Fail("Division by zero should throw an exception."); 
} 
catch(std::invalid_argument) 
{ 
    //test passed 
}