2011-01-05 25 views
9

Chúng tôi muốn nâng cấp các dự án của chúng tôi từ ASP.NET MVC 2 lên 3. Hầu hết các thử nghiệm của chúng tôi đã thành công, nhưng có một số thất bại trên ValueProviderFactories.Factories.GetValueProvider(context).Làm thế nào để kiểm tra đơn vị ValueProviderFactories trong ASP.NET MVC3?

Dưới đây là một lớp thử nghiệm đơn giản khắc phục sự cố.

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

Ngoại lệ "Tham chiếu đối tượng không được đặt thành thể hiện của đối tượng". được ném khi ValueProviderFactories.Factories.GetValueProvider(context) được gọi. Stacktrace trông như thế này:

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# 

Tôi muốn biết lý do tại sao nó ném ngoại lệ và cưa:

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

Vì vậy, chúng ta trở lại trong quá khứ khi chúng ta còn phụ thuộc vào HttpContext.Current? Làm thế nào để workaround nó?

+0

Tôi gặp vấn đề tương tự. 1 cho một câu hỏi hay. –

+0

Tôi có cùng nhu cầu để cảm ơn bạn. Một điểm cần đề cập, chỉ cần thiết lập RouteData mới() vẫn có thể ném lỗi. Để khắc phục nó, tôi đã phải thêm một "điều khiển" và "hành động" chìa khóa/giá trị cho các routedata trước khi ăn nó. – uadrive

Trả lời

8

Điều này có thể dễ dàng được giải quyết bằng cách giả mạo ValueProviders truy cập HttpContext với người bỏ qua nó.

Tôi đã giải thích mọi thứ trong bài đăng trên blog của mình: Unit test actions with ValueProviderFactories in ASP.NET MVC3.

Điều quan trọng là mã này:

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

Vì vậy, nó có thể được sử dụng như:

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

Đó là thực sự rất đơn giản :)

CẬP NHẬT: Như đã đề cập trong ý kiến bạn nên nhớ:

  1. đặt thuộc tính cho một số giá trị không null, nếu không JsonValueProviderFactory sẽ ném ngoại lệ. Tôi thích tạo một mô hình và đặt giá trị mặc định ở đó.
  2. thay thế HttpFileCollectionValueProviderFactory vì nó có thể được sử dụng trong quá trình ràng buộc.
  3. xem các phụ thuộc khác mà bạn có thể có trong dự án.
+1

Làm tốt lắm! Lưu ý: bạn phải đặt thuộc tính ctx.HttpContext.Request.ContentType thành một số giá trị không null, nếu không thì JsonValueProviderFactory sẽ ném ngoại lệ. – dkl

+0

Sự cố được giải quyết, cảm ơn :) – stej

+1

Tôi cũng phải thay thế 'HttpFileCollectionValueProviderFactory' để làm việc này. –

0

Bạn không nên gọi ValueProviderFactories.Factories, ModelBinders.Binders hoặc bất kỳ trình truy cập tĩnh nào khác từ bên trong một thử nghiệm đơn vị. Đó chính xác là lý do tại sao ModelBindingContext.ValueProvider tồn tại - để bạn có thể cung cấp một IValueProvider giả lập của chính bạn, thay vì dựa vào các giá trị mặc định tĩnh (giả sử đường dẫn MVC đang chạy).

+4

Chế nhạo 'IValueProvider' là một số lượng công việc vô lý. Nó sẽ yêu cầu reimplementing hàng chục tính năng ASP.NET MVC. Nó thậm chí không vui như thế nào nó được sử dụng để được kiểm tra, và bây giờ nó là không. –

Các vấn đề liên quan