2010-01-02 79 views
21

我已经写了自定义的模型绑定,使用ASP.NET MVC 2.本模型绑定绑定仅有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单元测试来测试此模型活页夹吗?花了一些小时Google搜索,找到几个例子(http://www.hanselman.com/blog/SplittingDateTimeUnitTestingASPNETMVCCustomModelBinders.aspx),但这个例子是为MVC1,并且在使用MVC2时不工作。

我感谢您的帮助。

回答

41

我修改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); 
} 
+0

你的回答让我从MVC源代码中解脱出来。我试图做同样的更新,并得出几乎相同的结果。不幸的是,我没有在'ModelBindingContext'上设置'ModelMetaData'。没有它,你会在'BindModel(ControllerContext controllerContext,ModelBindingContext bindingContext)'上得到一个不起眼的'NullReferenceException'。 – patridge 2010-05-12 21:06:13

+0

谢谢你。它很好地为我清理了一些东西。 – 2010-12-09 19:40:47

+0

我正要创建一个自定义的ValueProvider,但是要感谢你提到的NameValueCollectionValueProvider。这很有用。谢谢。 – Mani 2011-03-25 10:04:58

1

一般的方法是创建一个模拟ControllerContext,模拟ModelBindingContext和模拟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 

什么问题(S)?

+0

只需要嘲讽ControllerContext,ModelBindingContext和的PropertyDescriptor的一个例子。 是的,我使用NHibernate,但我知道如何抽象和模拟这一层。 – 2010-01-03 11:24:18

+0

模仿'ModelBindingContext'的一个问题是其最重要的属性('ModelType')是非虚拟的,这意味着基于继承的框架(例如Moq)不能模拟它的行为。 – 2013-05-23 01:50:08