2010-01-02 36 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