1

對MVC來說很新,所以希望這是一個簡單的問題。在單元測試中使用自定義的ModelMetadataProvider

我寫了一個自定義綁定屬性,需要訪問httpContext。爲了在單元測試期間注入模擬httpContext,我編寫了一個InjectingMetadataProvider,它在我的任何自定義屬性上填充了Context屬性。

我設法得到這個在下面的測試工作:

[TestMethod] 
public void Marker_ShouldBind_Id() 
{ 
    // Arrange 
    var formCollection = new NameValueCollection 
    { 
     { "id", "2" } 
    }; 

    var context = new Mock<HttpContextBase>(); 
    context.Setup(c => c.User).Returns((IPrincipal)null); 

    var metaProvider = new InjectingMetadataProvider(context.Object); 
    ModelMetadataProviders.Current = metaProvider; //why do I need this? 

    var bindingContext = new ModelBindingContext 
    { 
     ModelName  = string.Empty, 
     ValueProvider = new NameValueCollectionValueProvider(formCollection, null), 
     ModelMetadata = metaProvider.GetMetadataForType(null, typeof(Marker)), 
    }; 

    var binder = new DefaultModelBinder(); 

    // Act 
    var marker = (Marker)binder.BindModel(new ControllerContext(), bindingContext); 

    // Assert 
    marker.Id.Should().Be(2); 
} 

不過,如果我註釋掉設置行我InjectingMetadataProvider到​​,然後我InjectingMetadataProvider.CreateMetadata()覆蓋被移交屬性的空白名單,所以測試失敗,因爲我的自定義屬性沒有得到它們的上下文集。

爲什麼我需要將它設置爲Current當我明確地使用它?我不想在測試中設置靜態內容。

我可能在做一些愚蠢的事情,因爲我現在在黑暗中感覺有點不舒服,因爲我對框架不熟悉。

+0

下面的代碼對於爲什麼必須指定ModelMetadataProviders.Current有意義嗎?你可以在上下文中看到這個方法[這裏](https://github.com/ASP-NET-MVC/ASP.NET-Mvc-3/blob/master/mvc3/src/SystemWebMvc/Mvc/DefaultModelBinder.cs)。 – barry

回答

1

在DefaultModelBinder中,調用BindComplexElementalModel時會創建一個新的綁定上下文。請注意,它從ModelMetadataProviders.Current獲取元數據,而不是您的自定義模型元數據提供程序。

internal ModelBindingContext CreateComplexElementalModelBindingContext(ControllerContext controllerContext, ModelBindingContext bindingContext, object model) { 
     BindAttribute bindAttr = (BindAttribute)GetTypeDescriptor(controllerContext, bindingContext).GetAttributes()[typeof(BindAttribute)]; 
     Predicate<string> newPropertyFilter = (bindAttr != null) 
      ? propertyName => bindAttr.IsPropertyAllowed(propertyName) && bindingContext.PropertyFilter(propertyName) 
      : bindingContext.PropertyFilter; 

     ModelBindingContext newBindingContext = new ModelBindingContext() { 
      ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, bindingContext.ModelType), 
      ModelName = bindingContext.ModelName, 
      ModelState = bindingContext.ModelState, 
      PropertyFilter = newPropertyFilter, 
      ValueProvider = bindingContext.ValueProvider 
     }; 

     return newBindingContext; 
    } 
相關問題