【问题标题】:Unit testing custom model binder in ASP.NET MVC 2ASP.NET MVC 2 中的单元测试自定义模型绑定器
【发布时间】:2010-01-02 19:50:17
【问题描述】:

我在项目中编写了自定义模型绑定器,它使用 ASP.NET MVC 2。这个模型绑定器只绑定模型的 2 个字段:

public class TaskFormBinder : DefaultModelBinder
{
    protected override void BindProperty(ControllerContext controllerContext,
        ModelBindingContext bindingContext,
        PropertyDescriptor propertyDescriptor)
    {           
        if (propertyDescriptor.Name == "Type")
        {
            var value = bindingContext.ValueProvider.GetValue("Type");
            var typeId = value.ConvertTo(typeof(int));
            TaskType foundedType;
            using (var nhSession = Domain.GetSession())
            {
                foundedType = nhSession.Get<TaskType>(typeId);
            }
            if (foundedType != null)
            {
                SetProperty(controllerContext, bindingContext, propertyDescriptor, foundedType);
            }
            else
            {
                AddModelBindError(bindingContext, propertyDescriptor);
            }
            return;
        }
        if (propertyDescriptor.Name == "Priority")
        { /* Other field binding ... */
            return;
        }
        base.BindProperty(controllerContext, bindingContext, propertyDescriptor);
    }
}

如何使用标准 VS 单元测试来测试这个模型绑定器?花了几个小时在谷歌上搜索,找到了几个示例 (http://www.hanselman.com/blog/SplittingDateTimeUnitTestingASPNETMVCCustomModelBinders.aspx),但这个示例适用于 MVC1,在使用 MVC2 时不起作用。

感谢您的帮助。

【问题讨论】:

    标签: asp.net-mvc unit-testing modelbinders


    【解决方案1】:

    我已修改 Hanselman's MVC 1 example 以测试 ASP.Net MVC 2 模型绑定器...

    [Test]
    public void Date_Can_Be_Pulled_Via_Provided_Month_Day_Year()
    {
        // Arrange
        var formCollection = new NameValueCollection { 
            { "foo.month", "2" },
            { "foo.day", "12" },
            { "foo.year", "1964" }
        };
    
        var valueProvider = new NameValueCollectionValueProvider(formCollection, null);
        var modelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, typeof(FwpUser));
    
        var bindingContext = new ModelBindingContext
        {
            ModelName = "foo",
            ValueProvider = valueProvider,
            ModelMetadata = modelMetadata
        };
    
        DateAndTimeModelBinder b = new DateAndTimeModelBinder { Month = "month", Day = "day", Year = "year" };
        ControllerContext controllerContext = new ControllerContext();
    
        // Act
        DateTime result = (DateTime)b.BindModel(controllerContext, bindingContext);
    
        // Assert
        Assert.AreEqual(DateTime.Parse("1964-02-12 12:00:00 am"), result);
    }
    

    【讨论】:

    • 您的回答使我免于在 MVC 源代码中四处游荡。我尝试进行相同的更新并得出几乎相同的结果。不幸的是,我没有在ModelBindingContext 上设置ModelMetaData。没有它,你会在BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 上得到一个不起眼的NullReferenceException
    • 我正要创建一个自定义 ValueProvider,但感谢您提到的 NameValueCollectionValueProvider。这很有用。谢谢。
    • 这里值得为像我这样的其他人指出一点:) 分配给 ModelBindingContext 的 ModelName 很重要,不能简单地是任意名称。我使用 string.Empty 来避免任何混淆。
    【解决方案2】:

    一般的做法是创建一个mock ControllerContext、mock ModelBindingContext、mock PropertyDescriptor,然后调用方法。

    如果您的模型绑定器使用其他服务,它看起来像您的服务(您正在使用 NHibernate?),那么您必须将它们抽象出来并提供它们的模拟。

    单元测试代码如下所示:

    // Arrange
    ControllerContext mockControllerContext = ...;
    ModelBindingContext mockModelBindingContext = ...;
    PropertyDescriptor mockPropertyDescriptor = ...;
    SomeService mockService = ...;
    
    TaskFormBinder taskFormBinder = new TaskFormBinder();
    taskFormBinder.Service = mockService;
    
    // Act
    taskFormBinder.BindProperty(
        mockControllerContext, mockModelBindingContext, mockPropertyDescriptor);
    
    // Assert
    // ... here you need to inspect the values in the model binding context to see that it set the right properties
    

    您在编写单元测试时遇到了什么问题?

    【讨论】:

    • 只需要一个模拟ControllerContext、ModelBindingContext和PropertyDescriptor的例子。是的,我使用 NHibernate,但我知道这一层是多么抽象和模拟。
    • 模拟 ModelBindingContext 的一个问题是它最重要的属性 (ModelType) 是非虚拟的,这意味着基于继承的框架(例如 Moq)不能模拟它的行为。
    猜你喜欢
    • 1970-01-01
    • 2010-12-20
    • 1970-01-01
    • 2011-04-27
    • 1970-01-01
    • 1970-01-01
    • 2019-05-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多