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


97

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

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

Assert.IsNotNull(exception);

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

जवाबों:


137

मेरे पास विभिन्न पैटर्न हैं जो मैं उपयोग करता हूं। मैं 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 )
        );
    }
}

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

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

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

FYI करें - मैं xUnit का उपयोग करने के लिए आगे बढ़ा हूं जिसमें एक दृढ़ता से टाइप की गई Assert.Throwsविधि है जो इन दोनों मामलों को कवर करती है।
tvanfosson

ExpectedException विशेषता परीक्षण के लिए बुरा और दिनांकित तरीका है कि क्या अपवाद फेंके गए हैं। नीचे मेरा पूरा जवाब देखें।
bytedev

43

अब, 2017, आप इसे नए MSTest V2 फ्रेमवर्क के साथ आसान बना सकते हैं :

Assert.ThrowsException<Exception>(() => myClass.MyMethodWithError());

//async version
await Assert.ThrowsExceptionAsync<SomeException>(
  () => myObject.SomeMethodAsync()
);

यह तभी सफल होगा जब System.Exceptionफेंक दिया जाएगा। कोई भी अन्य, जैसे System.ArgumentExceptionकि परीक्षा में असफल हो जाएगा।
sschoof

2
यदि आप किसी अन्य प्रकार के अपवाद की अपेक्षा कर रहे हैं, तो आपको इसके लिए परीक्षण करना चाहिए ... आपके उदाहरण में, आप जोर से करते हैं: Assert.ThrowsException <ArgumentException> () => myClass.MyMethodWithError ());
Icaro Bombonato

2
नोट करने के लिए कुछ महत्वपूर्ण यह है कि प्रदान किए जाने का उपयोग Assert.ThrowsException<MyException>पूरी तरह से प्रदान किए गए बहुत अपवाद प्रकार के खिलाफ परीक्षण करेगा, और इसके व्युत्पन्न अपवाद प्रकारों में से कोई भी नहीं। मेरे उदाहरण में, यदि परीक्षण किया Subकिया गया था Throwएक MyInheritedException(आधार वर्ग से प्राप्त प्रकार MyException), तो परीक्षण होगा असफल
आमा

यदि आप अपने परीक्षण को व्यापक बनाना चाहते हैं और एक अपवाद प्रकार के साथ-साथ इसके व्युत्पन्न प्रकारों को स्वीकार करना चाहते हैं, तो ए का उपयोग करें Try { SubToTest(); Assert.Fail("...") } Catch (AssertFailedException e) {throw;} Catch (MyException e) {...}Catch (AssertFailedException e) {throw;}(Allfek से cf. टिप्पणी) के सर्वोच्च महत्व पर ध्यान दें
Ama

17

मैं यहां नया हूं और टिप्पणी या डाउनवोट करने के लिए प्रतिष्ठा नहीं है, लेकिन एंडी व्हाइट के उत्तर में उदाहरण में एक दोष बताना चाहता था :

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

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

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


15

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

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

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

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

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

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

संपादित करें

नीचे मैथ्यू की टिप्पणी का एक उदाहरण देने के लिए, जेनेरिक की वापसी 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);

2
रॉय ओशेरोव ने द आर्ट ऑफ़ यूनिट टेस्टिंग, सेकेंड एड, सेक्शन 2.6.2 में इसकी सिफारिश की है।
अवी

2
मुझे पसंद है Assert.Throws, इसके अलावा यह अपवाद भी लौटाता है ताकि आप अपवाद पर आगे के दावे लिख सकें।
मैथ्यू

सवाल MSTest नहीं NUnit के लिए था।
बट्टेव

@ नशवान ओपी के मूल प्रश्न में वह योग्यता नहीं थी, और टैगिंग अभी भी एमएस-टेस्ट को उत्तीर्ण नहीं करती है। जैसा कि यह खड़ा है, यह एक सी #,। नेट, यूनिट-परीक्षण प्रश्न है।
स्टुअर्टएलसी

11

दुर्भाग्यवश MSTest STILL में वास्तव में ExpectedException का गुण है (बस दिखाता है कि MS किस प्रकार MSTest की बहुत परवाह करता है) जो IMO बहुत ही भयानक है क्योंकि यह Arrange / Act / Assert पैटर्न को तोड़ता है और यह आपको कोड की उस पंक्ति को निर्दिष्ट करने की अनुमति नहीं देता है जिससे आप अपवाद की अपेक्षा करते हैं। घटित होना।

जब मैं 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));

10

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

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

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);
    }
}

4

ExpectedExceptionAttribute के साथ परीक्षण को चिह्नित करें (यह NUnit या MSTest में शब्द है, अन्य इकाई परीक्षण रूपरेखा के उपयोगकर्ताओं को अनुवाद करने की आवश्यकता हो सकती है)।


ExpectedExceptionAttribute का उपयोग न करें (नीचे मेरी पोस्ट में दिया गया कारण)। NUnit में Assert.Throws है <YourException> () और MSTest के लिए नीचे मेरी AssertException क्लास जैसी किसी चीज़ का उपयोग करें।
14

3

अधिकांश .net इकाई परीक्षण ढाँचों के साथ आप परीक्षण पद्धति पर एक [ExpectedException] विशेषता डाल सकते हैं। हालाँकि यह आपको नहीं बता सकता है कि अपवाद उस बिंदु पर हुआ है जिसकी आपने अपेक्षा की थी। वहीं 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] के बराबर है


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

0

NUnit के स्वच्छ प्रतिनिधि सिंटैक्स का उपयोग करके सुझाव दें ।

परीक्षण के लिए उदाहरण ArgumentNullExeption:

[Test]
[TestCase(null)]
public void FooCalculation_InvalidInput_ShouldThrowArgumentNullExeption(string text)
{
    var foo = new Foo();
    Assert.That(() => foo.Calculate(text), Throws.ArgumentNullExeption);

    //Or:
    Assert.That(() => foo.Calculate(text), Throws.Exception.TypeOf<ArgumentNullExeption>);
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.