ASP.NET MVC में नियंत्रक का परीक्षण करने वाली इकाई का कोई वास्तविक मूल्य है?


33

मुझे उम्मीद है कि यह सवाल कुछ दिलचस्प जवाब देता है क्योंकि यह एक है जिसने मुझे थोड़ी देर के लिए उकसाया है।

ASP.NET MVC में नियंत्रक का परीक्षण करने वाली इकाई का कोई वास्तविक मूल्य है?

मेरा मतलब है कि ज्यादातर समय, (और मैं कोई प्रतिभाशाली नहीं हूं), मेरे नियंत्रक तरीके हैं, यहां तक ​​कि उनके सबसे जटिल कुछ इस पर हैं:

public ActionResult Create(MyModel model)
{
    // start error list
    var errors = new List<string>();

    // check model state based on data annotations
    if(ModelState.IsValid)
    {
        // call a service method
        if(this._myService.CreateNew(model, Request.UserHostAddress, ref errors))
        {
            // all is well, data is saved, 
            // so tell the user they are brilliant
            return View("_Success");
        }
    }

    // add errors to model state
    errors.ForEach(e => ModelState.AddModelError("", e));

    // return view
    return View(model);
}

अधिकांश हेवी-लिफ्टिंग MVC पाइपलाइन या मेरी सेवा लाइब्रेरी द्वारा की जाती है।

तो शायद सवाल पूछने के लिए हो सकता है:

  • इस विधि का परीक्षण करने वाली इकाई का मूल्य क्या होगा?
  • यह एक NullReferenceException पर Request.UserHostAddressऔर उसके ModelStateसाथ नहीं टूटेगा ? क्या मुझे इनका मजाक उड़ाने की कोशिश करनी चाहिए?
  • अगर मैं इस विधि को फिर से उपयोग करने योग्य "सहायक" (जो मुझे शायद यह करना चाहिए कि मैं इसे कितनी बार कर रहा हूं!) में अपवर्तक करता हूं, तो यह परीक्षण करेगा कि जब मैं वास्तव में परीक्षण कर रहा हूं तो यह भी सार्थक होगा कि ज्यादातर "पाइपलाइन" जो है! शायद, यह Microsoft द्वारा जीवन के एक इंच के भीतर परीक्षण किया गया है?

मुझे लगता है कि मेरी बात वास्तव में है, निम्न करना बिल्कुल व्यर्थ और गलत लगता है

[TestMethod]
public void Test_Home_Index()
{
    var controller = new HomeController();
    var expected = "Index";
    var actual = ((ViewResult)controller.Index()).ViewName;
    Assert.AreEqual(expected, actual);
}

जाहिर है मैं इस अतिशयोक्तिपूर्ण व्यर्थ उदाहरण के साथ विरोध कर रहा हूँ, लेकिन किसी को भी यहाँ जोड़ने के लिए कोई ज्ञान है?

इसके लिए तत्पर ... धन्यवाद।


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

जवाबों:


18

यहां तक ​​कि कुछ सरल के लिए, एक इकाई परीक्षण कई उद्देश्यों की सेवा करेगा

  1. आत्मविश्वास, जो लिखा गया था वह अपेक्षित आउटपुट के अनुरूप है। यह सत्यापित करने के लिए तुच्छ लग सकता है कि यह सही दृश्य देता है, लेकिन परिणाम वस्तुगत साक्ष्य है कि आवश्यकता पूरी हो गई थी
  2. प्रतिगमन परीक्षण। क्या विधि को बदलने की आवश्यकता है, आपके पास अपेक्षित आउटपुट के लिए अभी भी एक इकाई परीक्षण है। हां, आउटपुट में बदलाव हो सकता है और इसका परिणाम भंगुर परीक्षा के रूप में सामने आता है, लेकिन यह अभी भी संयुक्त राष्ट्र के प्रबंधित परिवर्तन नियंत्रण के खिलाफ है

उस विशेष कार्रवाई के लिए मैं निम्नलिखित के लिए परीक्षण करूँगा

  1. यदि _myService शून्य है, तो क्या होगा?
  2. क्या होता है अगर _myService.Create एक अपवाद फेंकता है, क्या यह विशिष्ट लोगों को संभालने के लिए फेंक देता है?
  3. क्या एक सफल _myService.Create _Success दृश्य लौटाता है?
  4. क्या मॉडलस्टैट तक त्रुटियां प्रचारित हैं?

आपने NullReferenceException के लिए अनुरोध और मॉडल की जाँच करने का उल्लेख किया है और मुझे लगता है कि ModelState.IsValid मॉडल के लिए NullReference को संभालने का ध्यान रखेगा।

अनुरोध का मज़ाक उड़ाना आपको अशक्त अनुरोध के विरुद्ध रक्षा करने की अनुमति देता है जो आम तौर पर मेरे विचार से उत्पादन में असंभव है, लेकिन एक यूनिट टेस्ट में हो सकता है। एक इंटीग्रेशन टेस्ट में यह आपको अलग-अलग यूजरहॉस्टड्रेस मान प्रदान करने की अनुमति देगा (नियंत्रण के संबंध में एक उपयोगकर्ता अभी भी इनपुट है जहां तक ​​नियंत्रण है और तदनुसार परीक्षण किया जाना चाहिए)


हाय केविन, जवाब देने के लिए समय निकालने के लिए धन्यवाद। मैं यह देखने के लिए थोड़ी देर के लिए जा रहा हूं कि कोई और किसी चीज के साथ आता है या नहीं, लेकिन अब तक तुम्हारा सबसे तार्किक / स्पष्ट है।
लिवरपूल

Spifty। खुशी है कि यह आपकी मदद की।
केविन

3

मेरे नियंत्रक बहुत छोटे हैं। नियंत्रकों में अधिकांश "तर्क" को फ़िल्टर विशेषताओं (अंतर्निहित और हाथ से लिखे गए) का उपयोग करके नियंत्रित किया जाता है। इसलिए मेरे नियंत्रक के पास आमतौर पर केवल मुट्ठी भर नौकरियां हैं:

  • HTTP क्वेरी स्ट्रिंग्स, फॉर्म वैल्यू आदि से मॉडल बनाएं।
  • कुछ बुनियादी सत्यापन करें
  • मेरे डेटा या व्यावसायिक स्तर पर कॉल करें
  • उत्पन्न करें ActionResult

ज्यादातर मॉडल बाइंडिंग ASP.NET MVC द्वारा स्वचालित रूप से की जाती है। DataAnnotations मेरे लिए अधिकांश सत्यापन को संभालता है, भी।

यहां तक ​​कि परीक्षण करने के लिए बहुत कम के साथ, मैं अभी भी उन्हें आमतौर पर लिखता हूं। मूल रूप से, मैं परीक्षण करता हूं कि मेरे रिपॉजिटरी को बुलाया जाता है और सही ActionResultप्रकार वापस किया जाता है। मेरे पास ViewResultयह सुनिश्चित करने के लिए एक सुविधाजनक तरीका है कि सही दृश्य पथ वापस आ गया है और दृश्य मॉडल वह तरीका दिखता है जिसकी मैं अपेक्षा करता हूं। मेरे पास सही नियंत्रक / कार्रवाई की जांच करने के लिए एक और सेट है RedirectToActionResult। मेरे पास अन्य परीक्षण हैं JsonResult, आदि आदि।

Controllerकक्षा को उप-वर्गीकृत करने का एक दुर्भाग्यपूर्ण परिणाम यह है कि यह HttpContextआंतरिक रूप से उपयोग करने वाली बहुत सारी सुविधा प्रदान करता है । इससे कंट्रोलर को यूनिट टेस्ट करना मुश्किल हो जाता है। इस कारण से, मैं आम तौर पर HttpContextएक इंटरफेस के पीछे-निर्भर कॉल करता हूं और उस इंटरफेस को नियंत्रक के निर्माता को सौंपता हूं (मैं मेरे लिए अपने नियंत्रक बनाने के लिए निन्जेक्ट वेब एक्सटेंशन का उपयोग करता हूं)। यह इंटरफ़ेस आमतौर पर जहां मैं सत्र, कॉन्फ़िगरेशन सेटिंग्स, IPrinciple और URL सहायकों तक पहुंचने के लिए सहायक गुण रखता हूं।

इसमें बहुत अधिक परिश्रम लगता है, लेकिन मुझे लगता है कि यह इसके लायक है।


जवाब देने के लिए समय निकालने के लिए धन्यवाद, लेकिन सीधे 2 मुद्दे। सबसे पहले, यूनिट परीक्षणों में "सहायक तरीके" v.dangerous हैं। दूसरे, "परीक्षण करें कि मेरे रिपॉजिटरी कहा जाता है" - क्या आप निर्भरता इंजेक्शन के माध्यम से मतलब है?
लिवरपूल

सुविधा के तरीके खतरनाक क्यों होंगे? मेरे पास एक BaseControllerTestsवर्ग है जहां वे सभी रहते हैं। मैं अपनी रिपॉजिटरी का मजाक उड़ाता हूं। मैं उन्हें Ninject का उपयोग करने में प्लग करता हूं।
ट्रैविस पार्क

यदि आपने कोई त्रुटि या अपने सहायक / गलत धारणा को बनाया है तो क्या होगा? मेरा दूसरा बिंदु यह था कि, केवल एक एकीकरण परीक्षण (यानी एंड-टू-एंड) "परीक्षण" कर सकता है या नहीं, क्या आपके रिपॉजिटरी को कहा जाता है। एक इकाई परीक्षण में आप "नई-अप" या अपने रिपॉजिटरी को मैन्युअल रूप से वैसे भी मॉक करेंगे।
लिवरपूल

आप कंस्ट्रक्टर को रिपॉजिटरी पास करते हैं। आप परीक्षण के दौरान इसका मजाक उड़ाते हैं। आप सुनिश्चित करें कि नकली उम्मीद के मुताबिक काम किया है। सहायकों ने केवल ActionResultउत्तीर्ण यूआरएल, मॉडल आदि का निरीक्षण करने के लिए पुनर्निर्माण किया है
ट्रैविस पार्क

ओके फेयर काफी - मुझे थोड़ा गलत लगा कि आपको "परीक्षण से क्या मतलब है कि मेरे रिपॉजिटरी कहलाते हैं"।
लीवरपूल्सनंबर

2

स्पष्ट रूप से कुछ नियंत्रक इससे कहीं अधिक जटिल हैं, लेकिन आपके उदाहरण पर पूरी तरह आधारित हैं:

यदि MyService एक अपवाद फेंकता है तो क्या होता है?

अलग नोट के रूप में।

इसके अलावा, मैं संदर्भ द्वारा एक सूची पास करने की बुद्धिमत्ता पर सवाल उठाऊंगा (यह अनावश्यक है क्योंकि c # वैसे भी संदर्भ से गुजरता है, लेकिन भले ही ऐसा न हो) - एक त्रुटि कार्रवाई (कार्रवाई) को पारित करना जो सेवा तब त्रुटि संदेशों को पंप करने के लिए उपयोग कर सकती है जो तब आप चाहते हैं, लेकिन आप इसे सूची में जोड़ना चाहते हैं, (शायद आप एक मॉडल त्रुटि जोड़ना चाहते हैं, शायद आप इसे लॉग इन करना चाहते हैं) को संभाला जा सकता है।

आपके उदाहरण में:

रेफ त्रुटियों के बजाय, उदाहरण के लिए (string s) => ModelState.AddModelError ("", s) करें।


उल्लेख के लायक है, यह मान लेता है कि आपकी सेवा उसी एप्लिकेशन में निवास कर रही है अन्यथा क्रमबद्धता के मुद्दे चलन में आ जाएंगे।
माइकल

सेवा एक अलग dll में होगी। लेकिन वैसे भी, आप शायद सही "रेफरी" हैं। आपके अन्य बिंदु पर, यह कोई फर्क नहीं पड़ता कि myService एक अपवाद फेंकता है। मैं myService का परीक्षण नहीं कर रहा हूं - मैं अलग-अलग तरीकों का परीक्षण करूंगा। मैं विशुद्ध रूप से ActionResult "Unit" के परीक्षण के बारे में बात कर रहा हूँ (शायद) एक mocked myService।
लीवरपूलसंबर

क्या आपके पास आपकी सेवा और आपके नियंत्रक के बीच 1: 1 मैपिंग है? यदि नहीं, तो क्या कुछ नियंत्रक कई सेवा कॉल का उपयोग करते हैं? यदि हां, तो आप उन इंटरैक्शन का परीक्षण कर सकते हैं?
माइकल

नहीं। दिन के अंत में, सेवा के तरीके इनपुट लेते हैं (आमतौर पर एक दृश्य मॉडल या यहां तक ​​कि स्ट्रिंग्स / इन्ट्स), वे "सामान करते हैं", फिर झूठे होने पर एक बूल / त्रुटियां वापस करते हैं। नियंत्रक और सेवा परत के बीच कोई "प्रत्यक्ष" लिंक नहीं है। पूरी तरह से अलग हो गए हैं।
लिवरपूल

हां, मैं समझता हूं कि, मैं नियंत्रकों और सेवा परत के बीच संबंधपरक मॉडल को समझने की कोशिश कर रहा हूं - यह मानते हुए कि प्रत्येक नियंत्रक के पास एक समान सेवा पद्धति नहीं है तो यह इस कारण से खड़ा होगा कि कुछ नियंत्रकों को इसका उपयोग करने की आवश्यकता हो सकती है एक से अधिक सेवा पद्धति?
माइकल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.