2009-04-12 14 views
74

फेंक दिए जाएंगे, अपवाद के साथ अपवादों का परीक्षण करने का सबसे अच्छा तरीका क्या आपको लगता है कि यह अपवादों का परीक्षण करने का एक अच्छा तरीका है? कोई सुझाव?यह सुनिश्चित करने के लिए कि वे

Exception exception = null; 
try{ 
    //I m sure that an exeption will happen here 
} 
catch (Exception ex){ 
    exception = ex; 
} 

Assert.IsNotNull(exception); 

मैं एमएस टेस्ट का उपयोग कर रहा हूं।

उत्तर

114

की XUnit बराबर मैं विभिन्न पैटर्न के एक जोड़े है मैं उपयोग करता हूं। जब मैं अपवाद की अपेक्षा करता हूं तो अधिकांश समय ExpectedException विशेषता का उपयोग करता हूं। ज्यादातर मामलों के लिए यह पर्याप्त है, हालांकि, कुछ मामले हैं जब यह पर्याप्त नहीं है। अपवाद को पकड़ने योग्य नहीं हो सकता है - क्योंकि इसे प्रतिबिंबित करने वाली विधि द्वारा फेंक दिया जाता है - या शायद मैं अन्य स्थितियों को पकड़ना चाहता हूं, कहें कि एक लेनदेन वापस लुढ़का गया है या कुछ मूल्य अभी भी सेट किया गया है। इन मामलों में मैं इसे try/catch ब्लॉक में लपेटता हूं जो सटीक अपवाद की अपेक्षा करता है, यदि कोड सफल होता है और यह सुनिश्चित करने के लिए जेनेरिक अपवाद भी प्राप्त करता है कि एक अलग अपवाद फेंक दिया गया है तो Assert.Fail करता है।

पहला मामला:

[TestMethod] 
[ExpectedException(typeof(ArgumentNullException))] 
public void MethodTest() 
{ 
    var obj = new ClassRequiringNonNullParameter(null); 
} 

दूसरा मामला:

[TestMethod] 
public void MethodTest() 
{ 
    try 
    { 
     var obj = new ClassRequiringNonNullParameter(null); 
     Assert.Fail("An exception should have been thrown"); 
    } 
    catch (ArgumentNullException ae) 
    { 
     Assert.AreEqual("Parameter cannot be null or empty.", ae.Message); 
    } 
    catch (Exception e) 
    { 
     Assert.Fail(
      string.Format("Unexpected exception of type {0} caught: {1}", 
          e.GetType(), e.Message) 
     ); 
    } 
} 
+15

कई यूनिट परीक्षण ढांचे अपवाद के रूप में दावा विफलताओं को लागू करते हैं। तो दूसरे मामले में Assert.Fail() पकड़ (अपवाद) ब्लॉक द्वारा पकड़ा जाएगा, जो अपवाद संदेश छुपाएगा। आपको एक पकड़ (NUnit.Framework.AssertionException) {throw;} या इसी तरह की जोड़ने की आवश्यकता है - मेरा उत्तर देखें। – GrahamS

+0

@ ग्राहम - मैंने इसे अपने सिर के ऊपर से टाइप किया। आमतौर पर मैं इसके प्रकार के अलावा अपवाद संदेश भी प्रिंट करूंगा। मुद्दा यह है कि परीक्षण विफल हो जाएगा क्योंकि दूसरा हैंडलर दावा विफलता को पकड़ लेगा और त्रुटि पर जानकारी के साथ "refail" होगा। – tvanfosson

+1

हालांकि आपका कोड कार्यात्मक रूप से ध्वनि है, लेकिन मैं अपेक्षित एक्सेप्शन विशेषता का उपयोग करने की अनुशंसा नहीं करता (क्योंकि यह बहुत बाधा और त्रुटि-प्रवण है) या प्रत्येक परीक्षण में एक प्रयास/पकड़ ब्लॉक लिखने के लिए (क्योंकि यह बहुत जटिल और त्रुटि-प्रवण है)। एक अच्छी तरह से डिज़ाइन किए गए जोर विधि का उपयोग करें - या तो अपने परीक्षण ढांचे द्वारा प्रदान किया गया है या अपना खुद का लिखें। आप बेहतर कोड प्राप्त कर सकते हैं और आपको परीक्षण तकनीकों के रूप में अलग-अलग तकनीकों या एक से दूसरे में बदलने की आवश्यकता नहीं होगी। Http://stackoverflow.com/a/25084462/2166177 – steve

4

ExpectedExceptionAttribute के साथ परीक्षण को चिह्नित करें (यह एनयूनीट या एमएसटीएस्ट में शब्द है; अन्य यूनिट परीक्षण ढांचे के उपयोगकर्ताओं को अनुवाद करने की आवश्यकता हो सकती है)।

+0

ExpectedExceptionAttribute (नीचे मेरी पोस्ट में दिए गए कारण) का उपयोग न करें: यह नया MSTest V2 Framework के साथ आसान है। न्यूटिट ने जोर दिया है।() फेंकता है और एमएसटीएस्ट के लिए नीचे मेरे AssertException वर्ग की तरह कुछ उपयोग करें। – nashwan

2

अधिकांश .NET इकाई परीक्षण ढांचे के साथ आप परीक्षण विधि पर एक [अपेक्षित अपवाद] विशेषता डाल सकते हैं। हालांकि यह आपको यह नहीं बता सकता कि उस बिंदु पर अपवाद हुआ जिसकी आपने अपेक्षा की थी। यही वह जगह है जहां xunit.net मदद कर सकता है।

XUnit आप, Assert.Throws है, इसलिए आप इस तरह कर सकते हैं के साथ

:

[Fact] 
    public void CantDecrementBasketLineQuantityBelowZero() 
    { 
     var o = new Basket(); 
     var p = new Product {Id = 1, NetPrice = 23.45m}; 
     o.AddProduct(p, 1); 
     Assert.Throws<BusinessException>(() => o.SetProductQuantity(p, -3)); 
    } 

[तथ्य] है [TestMethod]

+0

यदि आपको एमएसटीएस्ट का उपयोग करना चाहिए (जिसे मुझे अक्सर नियोक्ता द्वारा मजबूर किया जाता है) तो नीचे मेरा जवाब देखें। – nashwan

9

ExpectedException विशेषता का उपयोग के लिए एक विकल्प, मैं कभी कभी अपने परीक्षण कक्षाओं के लिए दो उपयोगी तरीकों को परिभाषित के रूप में:

AssertThrowsException() एक प्रतिनिधि लेता है और दावा करता है कि यह अपेक्षित एम के साथ अपेक्षित अपवाद फेंकता है essage।

AssertDoesNotThrowException() एक ही प्रतिनिधि लेता है और दावा है कि यह एक अपवाद फेंक नहीं है।

यह युग्मन बहुत उपयोगी हो सकता है जब आप यह जांचना चाहते हैं कि एक मामले में एक अपवाद फेंक दिया गया है, लेकिन दूसरा नहीं।

उन्हें का उपयोग करना मेरी इकाई परीक्षण कोड इस प्रकार दिखाई देंगे:

ExceptionThrower callStartOp = delegate(){ testObj.StartOperation(); }; 

// Check exception is thrown correctly... 
AssertThrowsException(callStartOp, typeof(InvalidOperationException), "StartOperation() called when not ready."); 

testObj.Ready = true; 

// Check exception is now not thrown... 
AssertDoesNotThrowException(callStartOp); 

अच्छा और साफ है ना?इस प्रकार

मेरे AssertThrowsException() और AssertDoesNotThrowException() तरीकों एक आम आधार वर्ग पर परिभाषित कर रहे हैं:

protected delegate void ExceptionThrower(); 

/// <summary> 
/// Asserts that calling a method results in an exception of the stated type with the stated message. 
/// </summary> 
/// <param name="exceptionThrowingFunc">Delegate that calls the method to be tested.</param> 
/// <param name="expectedExceptionType">The expected type of the exception, e.g. typeof(FormatException).</param> 
/// <param name="expectedExceptionMessage">The expected exception message (or fragment of the whole message)</param> 
protected void AssertThrowsException(ExceptionThrower exceptionThrowingFunc, Type expectedExceptionType, string expectedExceptionMessage) 
{ 
    try 
    { 
     exceptionThrowingFunc(); 
     Assert.Fail("Call did not raise any exception, but one was expected."); 
    } 
    catch (NUnit.Framework.AssertionException) 
    { 
     // Ignore and rethrow NUnit exception 
     throw; 
    } 
    catch (Exception ex) 
    { 
     Assert.IsInstanceOfType(expectedExceptionType, ex, "Exception raised was not the expected type."); 
     Assert.IsTrue(ex.Message.Contains(expectedExceptionMessage), "Exception raised did not contain expected message. Expected=\"" + expectedExceptionMessage + "\", got \"" + ex.Message + "\""); 
    } 
} 

/// <summary> 
/// Asserts that calling a method does not throw an exception. 
/// </summary> 
/// <remarks> 
/// This is typically only used in conjunction with <see cref="AssertThrowsException"/>. (e.g. once you have tested that an ExceptionThrower 
/// method throws an exception then your test may fix the cause of the exception and then call this to make sure it is now fixed). 
/// </remarks> 
/// <param name="exceptionThrowingFunc">Delegate that calls the method to be tested.</param> 
protected void AssertDoesNotThrowException(ExceptionThrower exceptionThrowingFunc) 
{ 
    try 
    { 
     exceptionThrowingFunc(); 
    } 
    catch (NUnit.Framework.AssertionException) 
    { 
     // Ignore and rethrow any NUnit exception 
     throw; 
    } 
    catch (Exception ex) 
    { 
     Assert.Fail("Call raised an unexpected exception: " + ex.Message); 
    } 
} 
15

मैं यहाँ नया हूँ और टिप्पणी या downvote करने के लिए प्रतिष्ठा की जरूरत नहीं है, लेकिन एक दोष का कहना चाहते थे

try 
{ 
    SomethingThatCausesAnException(); 
    Assert.Fail("Should have exceptioned above!"); 
} 
catch (Exception ex) 
{ 
    // whatever logging code 
} 

सभी इकाई परीक्षण चौखटे मैं एक अपवाद फेंक कर, Assert.Fail काम करता है से परिचित हूँ में, तो सामान्य पकड़ वास्तव में परीक्षण की विफलता मुखौटा होगा: Andy White's reply में उदाहरण में। यदि SomethingThatCausesAnException() फेंक नहीं देता है, तो Assert.Fail होगा, लेकिन यह असफलता को इंगित करने के लिए परीक्षण धावक को कभी भी बबल नहीं करेगा।

यदि आपको अपेक्षित अपवाद (यानी, कुछ विवरणों को जोर देने के लिए, अपवाद पर संदेश/गुणों जैसे) को पकड़ने की आवश्यकता है, तो विशिष्ट अपेक्षित प्रकार को पकड़ना महत्वपूर्ण है, न कि आधार अपवाद वर्ग। इससे Assert.Fail बबल आउट अपवाद (यह मानते हुए कि आप एक ही प्रकार के अपवाद को फेंक नहीं रहे हैं जो आपके यूनिट परीक्षण ढांचे को फेंक रहा है), लेकिन फिर भी आपके SomethingThatCausesAnException() विधि द्वारा फेंक दिए गए अपवाद पर सत्यापन की अनुमति दें।

12

वी 2.5, NUnit के रूप में निम्न विधि-स्तर है परीक्षण अपवाद के लिए Assert रों:

Assert.Throws है, जो एक सटीक अपवाद प्रकार के लिए परीक्षण किया जाएगा:

Assert.Throws<NullReferenceException>(() => someNullObject.ToString()); 

और Assert.Catch है, जो एक के लिए परीक्षण किया जाएगा किसी दिए गए प्रकार का अपवाद, या इस प्रकार से प्राप्त अपवाद प्रकार:

Assert.Catch<Exception>(() => someNullObject.ToString()); 

एक तरफ, जब अपवाद फेंकने वाले यूनिट परीक्षण डीबग करते हैं, तो आप breaking on the exception से वीएस को रोकना चाहेंगे।

संपादित

बस नीचे दिए गए मैथ्यू की टिप्पणी, सामान्य Assert.Throws और Assert.Catch की वापसी का एक उदाहरण देने के लिए अपवाद है, जो आप तो आगे निरीक्षण के लिए जांच कर सकते हैं के प्रकार के साथ अपवाद है:

// The type of ex is that of the generic type parameter (SqlException) 
var ex = Assert.Throws<SqlException>(() => MethodWhichDeadlocks()); 
Assert.AreEqual(1205, ex.Number); 
+1

रॉय ओशरोव ने कला की यूनिट परीक्षण, द्वितीय संस्करण, खंड 2.6.2 में इसकी सिफारिश की है। – Avi

+2

मुझे 'Assert.Throws' पसंद है, इसके अलावा यह अपवाद देता है ताकि आप अपवाद पर आगे के दावे लिख सकें। – Matthew

+0

सवाल एमएसटीएस्ट नुनिट के लिए नहीं था। – nashwan

8

दुर्भाग्य MSTest अभी तक केवल वास्तव में ExpectedException विशेषता है क्योंकि यह व्यवस्था/अधिनियम/जोर पैटर्न टूट जाता है और इसे आप exac निर्दिष्ट करने के लिए अनुमति does not जो IMO बहुत भयंकर है (बस कितना एमएस MSTest परवाह से पता चलता है) कोड की कौन सी रेखा आप अपवाद की अपेक्षा करते हैं।

जब मैं उपयोग कर रहा हूँ (/ एक ग्राहक द्वारा मजबूर) MSTest उपयोग करने के लिए मैं हमेशा इस सहायक वर्ग का उपयोग करें:

public static class AssertException 
{ 
    public static void Throws<TException>(Action action) where TException : Exception 
    { 
     try 
     { 
      action(); 
     } 
     catch (Exception ex) 
     { 
      Assert.IsTrue(ex.GetType() == typeof(TException), "Expected exception of type " + typeof(TException) + " but type of " + ex.GetType() + " was thrown instead."); 
      return; 
     } 
     Assert.Fail("Expected exception of type " + typeof(TException) + " but no exception was thrown."); 
    } 

    public static void Throws<TException>(Action action, string expectedMessage) where TException : Exception 
    { 
     try 
     { 
      action(); 
     } 
     catch (Exception ex) 
     { 
      Assert.IsTrue(ex.GetType() == typeof(TException), "Expected exception of type " + typeof(TException) + " but type of " + ex.GetType() + " was thrown instead."); 
      Assert.AreEqual(expectedMessage, ex.Message, "Expected exception with a message of '" + expectedMessage + "' but exception with message of '" + ex.Message + "' was thrown instead."); 
      return; 
     } 
     Assert.Fail("Expected exception of type " + typeof(TException) + " but no exception was thrown."); 
    } 
} 

उपयोग के उदाहरण:

AssertException.Throws<ArgumentNullException>(() => classUnderTest.GetCustomer(null)); 
6

अब, 2017, आप कर सकते हैं

Assert.ThrowsException<Exception>(() => myClass.MyMethodWithError()); 
संबंधित मुद्दे