2010-01-02 14 views
21

Ich habe geschrieben benutzerdefinierten Modell Binder in Projekt, das ASP.NET MVC 2. binden Dieses Modell Bindemittel verwendet nur 2 Felder des Modells:Unit-Tests benutzerdefinierten Modell Binder in ASP.NET MVC 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); 
    } 
} 

Wie Kann ich diesen Modellbinder mit Standard-VS-Unit-Tests testen? Habe einige Stunden gegoogelt, paar Beispiele gefunden (http://www.hanselman.com/blog/SplittingDateTimeUnitTestingASPNETMVCCustomModelBinders.aspx), aber dieses Beispiel ist für MVC1 und funktioniert nicht, wenn MVC2 verwendet wird.

Ich schätze Ihre Hilfe.

Antwort

41

I Hanselman's MVC 1 example geändert haben ASP.Net MVC 2-Modell Bindemittel zu testen ...

[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

Ihre Antwort hat mich davor bewahrt, in der MVC-Quelle herumzudummeln. Ich habe versucht, das gleiche Update zu machen und kam fast zu dem gleichen Ergebnis. Leider habe ich 'ModelMetaData' nicht auf' ModelBindingContext' gesetzt. Ohne es erhalten Sie eine unbestimmte "NullReferenceException" auf "BindModel (ControllerContext controllerContext, ModelBindingContext bindingContext)". – patridge

+0

Danke dafür. Es hat mir einige Dinge klargemacht. –

+0

Ich wollte gerade einen benutzerdefinierten ValueProvider erstellen, aber dank des von Ihnen erwähnten NameValueCollectionValueProvider. Das war nützlich. Vielen Dank. – Mani

1

Der allgemeine Ansatz besteht darin, einen Mock ControllerContext, Mock ModelBindingContext und Mock PropertyDescriptor zu erstellen und dann die Methode aufzurufen.

Wenn Ihr Modellbinder andere Dienste verwendet, die Ihrer Ansicht nach (und Sie verwenden NHibernate?) Verwenden, dann müssen Sie diese abstrahieren und auch Mocks bereitstellen.

Die Unit-Test-Code wird wie folgt aussehen:

// 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 

Was für ein Problem (en) haben Sie den Unit-Test zu schreiben?

+0

brauchen nur ein Beispiel für spöttische Controller, ModelBindingContext und PropertyDescriptor. Ja, ich benutze NHibernate, aber ich weiß, wie abstrakt und mock diese Schicht. –

+0

Ein Problem beim Mocking von 'ModelBindingContext' ist, dass seine wichtigste Eigenschaft ('ModelType') nicht virtuell ist, was bedeutet, dass vererbungsbasierte Frameworks (z. B. Moq) ihr Verhalten nicht verspotten können. –

Verwandte Themen