9

हम अपनी परियोजनाओं को एएसपी.नेट एमवीसी 2 से 3 तक अपग्रेड करना चाहते थे। हमारे अधिकांश परीक्षण सफल हुए, लेकिन कुछ ऐसे हैं जो ValueProviderFactories.Factories.GetValueProvider(context) पर असफल हो जाते हैं।ASP.NET MVC3 में यूनिट परीक्षण ValueProviderFactories कैसे करें?

यहां एक साधारण टेस्ट क्लास है जो समस्या को प्रभावित करती है।

[TestFixture] 
public class FailingTest 
{ 
    [Test] 
    public void Test() 
    { 
    var type = typeof(string); 
    // any controller 
    AuthenticationController c = new AuthenticationController(); 
    var httpContext = new Mock<HttpContextBase>(); 
    var context = c.ControllerContext = new ControllerContext(httpContext.Object, new RouteData(), c); 

    IModelBinder converter = ModelBinders.Binders.GetBinder(type); 
    var bc = new ModelBindingContext 
    { 
     ModelName = "testparam", 
     ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, type), 
     ValueProvider = ValueProviderFactories.Factories.GetValueProvider(context) 
    }; 
    Console.WriteLine(converter.BindModel(context, bc)); 
    } 
} 

अपवाद "ऑब्जेक्ट संदर्भ किसी ऑब्जेक्ट के उदाहरण पर सेट नहीं है।" ValueProviderFactories.Factories.GetValueProvider(context) कहा जाता है जब फेंक दिया जाता है। स्टैकट्रेस इस तरह दिखता है:

Microsoft.Web.Infrastructure.dll!Microsoft.Web.Infrastructure.DynamicValidationHelper.ValidationUtility.CollectionReplacer.GetUnvalidatedCollections(System.Web.HttpContext context) + 0x23 bytes 
Microsoft.Web.Infrastructure.dll!Microsoft.Web.Infrastructure.DynamicValidationHelper.ValidationUtility.GetUnvalidatedCollections(System.Web.HttpContext context, out System.Collections.Specialized.NameValueCollection form, out System.Collections.Specialized.NameValueCollection queryString, out System.Collections.Specialized.NameValueCollection headers, out System.Web.HttpCookieCollection cookies) + 0xbe bytes  
System.Web.WebPages.dll!System.Web.Helpers.Validation.Unvalidated(System.Web.HttpRequest request) + 0x73 bytes 
System.Web.WebPages.dll!System.Web.Helpers.Validation.Unvalidated(System.Web.HttpRequestBase request) + 0x25 bytes 
System.Web.Mvc.DLL!System.Web.Mvc.FormValueProviderFactory..ctor.AnonymousMethod__0(System.Web.Mvc.ControllerContext cc) + 0x5a bytes 
System.Web.Mvc.DLL!System.Web.Mvc.FormValueProviderFactory.GetValueProvider(System.Web.Mvc.ControllerContext controllerContext) + 0xa0 bytes  
System.Web.Mvc.DLL!System.Web.Mvc.ValueProviderFactoryCollection.GetValueProvider.AnonymousMethod__7(System.Web.Mvc.ValueProviderFactory factory) + 0x4a bytes 
System.Core.dll!System.Linq.Enumerable.WhereSelectEnumerableIterator<System.Web.Mvc.ValueProviderFactory,<>f__AnonymousType2<System.Web.Mvc.ValueProviderFactory,System.Web.Mvc.IValueProvider>>.MoveNext() + 0x24d bytes 
System.Core.dll!System.Linq.Enumerable.WhereSelectEnumerableIterator<<>f__AnonymousType2<System.Web.Mvc.ValueProviderFactory,System.Web.Mvc.IValueProvider>,System.Web.Mvc.IValueProvider>.MoveNext() + 0x2ba bytes 
mscorlib.dll!System.Collections.Generic.List<System.Web.Mvc.IValueProvider>.List(System.Collections.Generic.IEnumerable<System.Web.Mvc.IValueProvider> collection) + 0x1d8 bytes  
System.Core.dll!System.Linq.Enumerable.ToList<System.Web.Mvc.IValueProvider>(System.Collections.Generic.IEnumerable<System.Web.Mvc.IValueProvider> source) + 0xb5 bytes 
System.Web.Mvc.DLL!System.Web.Mvc.ValueProviderFactoryCollection.GetValueProvider(System.Web.Mvc.ControllerContext controllerContext) + 0x24d bytes 
test.DLL!FailingTest.Test() Line 31 + 0xf9 bytes C# 

मैं कारण है कि यह अपवाद और देखा फेंकता में जानना चाहता था:

public static ValidationUtility.UnvalidatedCollections GetUnvalidatedCollections(HttpContext context) 
{ 
    return (ValidationUtility.UnvalidatedCollections) context.Items[_unvalidatedCollectionsKey]; 
} 

तो, जब हम HttpContext.Current पर निर्भर करते थे हम वापस अतीत में कर रहे हैं? इसे कैसे कामयाब करें?

+0

मेरे पास एक ही समस्या है। एक अच्छे सवाल के लिए +1। –

+0

मुझे वही ज़रूरत थी, इसलिए धन्यवाद। उल्लेख करने का एक बिंदु, बस नया रूटडेटा() सेट करना अभी भी त्रुटियों को फेंक सकता है। इसे दूर करने के लिए, मुझे इसे खाने से पहले रूटरटाटा में "नियंत्रक" और "क्रिया" कुंजी/मान जोड़ना पड़ा। – uadrive

उत्तर

8

इसे आसानी से प्रॉक्स-इन वैल्यूप्रोवाइडर्स द्वारा हल किया जा सकता है जो इसे अनदेखा करने के लिए HttpContext तक पहुंच सकते हैं।

मैंने अपने ब्लॉग पोस्ट में सबकुछ समझाया है: Unit test actions with ValueProviderFactories in ASP.NET MVC3

public static class ValueProviderFactoresExtensions { 
    public static ValueProviderFactoryCollection ReplaceWith<TOriginal>(this ValueProviderFactoryCollection factories, Func<ControllerContext, NameValueCollection> sourceAccessor) { 
     var original = factories.FirstOrDefault(x => typeof(TOriginal) == x.GetType()); 
     if (original != null) { 
      var index = factories.IndexOf(original); 
      factories[index] = new TestValueProviderFactory(sourceAccessor); 
     } 
     return factories; 
    } 

    class TestValueProviderFactory : ValueProviderFactory { 
     private readonly Func<ControllerContext, NameValueCollection> sourceAccessor; 


     public TestValueProviderFactory(Func<ControllerContext, NameValueCollection> sourceAccessor) { 
      this.sourceAccessor = sourceAccessor; 
     } 


     public override IValueProvider GetValueProvider(ControllerContext controllerContext) { 
      return new NameValueCollectionValueProvider(sourceAccessor(controllerContext), CultureInfo.CurrentCulture); 
     } 
    }   
} 

तो यह रूप में इस्तेमाल किया जा सकता है::

ValueProviderFactories.Factories 
    .ReplaceWith<FormValueProviderFactory>(ctx => ctx.HttpContext.Request.Form) 
    .ReplaceWith<QueryStringValueProviderFactory>(ctx => ctx.HttpContext.Request.QueryString); 

यह वास्तव में बहुत आसान :)

अद्यतन था: टिप्पणी में उल्लेख किया है

कुंजी इस कोड है आपको याद रखना चाहिए:

  1. कुछ गैर-शून्य मूल्य पर संपत्ति सेट करें, अन्यथा JsonValueProviderFactory अपवाद फेंक देगा। मैं एक नकली बनाना पसंद करता हूं और वहां डिफ़ॉल्ट मान सेट करता हूं।
  2. HttpFileCollectionValueProviderFactory को प्रतिस्थापित करें क्योंकि इसे बाध्यकारी के दौरान उपयोग किया जा सकता है।
  3. प्रोजेक्ट में आपके पास अन्य निर्भरताओं के लिए देखें।
+1

अच्छा काम! नोट: आपको ctx.HttpContext.Request.ContentType प्रॉपर्टी को कुछ शून्य-शून्य मान पर सेट करना होगा, अन्यथा JsonValueProviderFactory अपवाद फेंक देगा। – dkl

+0

समस्या हल हो गई, धन्यवाद :) – stej

+1

मुझे इसे काम करने के लिए 'HttpFileCollectionValueProviderFactory' को भी बदलना पड़ा। –

0

आपको यूनिट परीक्षण के भीतर से ValueProviderFactories.Factories, ModelBinders.Binders, या किसी अन्य स्थिर एक्सेसर को कॉल नहीं करना चाहिए। यही कारण है कि ModelBindingContext.ValueProvider मौजूद है - ताकि आप स्थैतिक चूक (जो एमवीसी पाइपलाइन चल रहा है) पर भरोसा करने के बजाय अपने स्वयं के सृजन का एक मजाकिया IValueProvider प्रदान कर सके।

+4

मॉकिंग 'IValueProvider' एक हास्यास्पद काम है। इसे एएसपी.नेट एमवीसी सुविधाओं के दर्जनों को पुन: कार्यान्वित करने की आवश्यकता होगी। यह भी मजाकिया नहीं है कि यह कैसे टेस्ट करने योग्य था, और अब यह नहीं है। –