【问题标题】:Using a custom ModelMetadataProvider in a unit test在单元测试中使用自定义 ModelMetadataProvider
【发布时间】:2012-11-02 09:39:16
【问题描述】:

对 MVC 很陌生,所以希望这是一个简单的问题。

我编写了一个需要访问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 设置为 ModelMetadataProviders.Current 的行,那么我的 InjectingMetadataProvider.CreateMetadata() 覆盖将获得一个空白的属性列表,因此测试失败,因为我的自定义属性没有得到它们的上下文集。

当我明确使用它时,为什么我需要将它设置为Current?我不想在我的测试中设置静态的东西。

我可能正在做一些愚蠢的事情,因为由于我对框架的不熟悉,我现在有点摸不着头脑。

【问题讨论】:

  • 下面的代码对为什么必须指定 ModelMetadataProviders.Current 有意义吗?您可以在上下文here 中看到此方法。

标签: asp.net-mvc unit-testing asp.net-mvc-4 moq modelmetadataprovider


【解决方案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;
    }

【讨论】:

    猜你喜欢
    • 2011-11-05
    • 2018-02-25
    • 2015-01-11
    • 1970-01-01
    • 2022-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多