Связыватель настраиваемой модели модульного тестирования в ASP.NET MVC 2

Я написал собственный связыватель модели в проекте, который использует 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? Потратил несколько часов на поиски в Google, нашел пару примеров (http://www.hanselman.com/blog/SplittingDateTimeUnitTestingASPNETMVCCustomModelBinders.aspx), но эти примеры предназначены для MVC1 и не работают при использовании MVC2.

Я ценю вашу помощь.


person Mike G.    schedule 02.01.2010    source источник


Ответы (2)


Я изменил пример Hanselman MVC 1, чтобы протестировать связующие модели 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);
}
person Russell Giddings    schedule 22.02.2010
comment
Ваш ответ спас меня от возни с исходным кодом MVC. Я попытался сделать такое же обновление и получил почти такой же результат. К сожалению, я не устанавливал ModelMetaData на ModelBindingContext. Без него вы получите невзрачный NullReferenceException на BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext). - person patridge; 13.05.2010
comment
Я собирался создать настраиваемый ValueProvider, но благодаря упомянутому вами NameValueCollectionValueProvider. Это было полезно. Спасибо. - person Mani; 25.03.2011
comment
Здесь есть кое-что, на что стоит обратить внимание другим людям вроде меня :) Имя ModelName, присвоенное ModelBindingContext, важно и не может быть просто произвольным именем. Я использую string.Empty, чтобы избежать путаницы. - person Jamie Dixon; 16.10.2012

Общий подход состоит в том, чтобы создать фиктивный 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

С какими проблемами вы сталкиваетесь при написании модульного теста?

person Eilon    schedule 02.01.2010
comment
Просто нужен пример имитации ControllerContext, ModelBindingContext и PropertyDescriptor. Да, я использую NHibernate, но я знаю, как абстрагироваться и издеваться над этим слоем. - person Mike G.; 03.01.2010
comment
Одна из проблем с издевательством ModelBindingContext заключается в том, что его наиболее важное свойство (ModelType) не является виртуальным, что означает, что фреймворки на основе наследования (например, Moq) не могут имитировать его поведение. - person Carl G; 23.05.2013