Как выполнить модульное тестирование связывателя модели с ModelMetadata - PullRequest
25 голосов
/ 18 февраля 2011

Как выполнить модульное тестирование пользовательского ModelBinder?

Вот код.

public class MagicBinder : DefaultModelBinder
    {

        public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            var boundModelObject = base.BindModel(controllerContext, bindingContext);

            var properties = bindingContext.ModelType.GetProperties().Where(a => a.CanWrite);
            foreach (var propertyInfo in properties)
            {
                object outValue = null;
                bindingContext.TryGetValue(propertyInfo.Name, propertyInfo.DeclaringType, out outValue);
                propertyInfo.SetValue(boundModelObject, outValue, null);
            }

            return boundModelObject;
        }
    }

А вот и сценарий тестирования.

[TestMethod]
public void TestFooBinding()
{
    var dict = new ValueProviderDictionary(null)
                   {
                       {"Number", new ValueProviderResult("2", "2", null)},
                       {"Test", new ValueProviderResult("12", "12", null)},
                   };

    var bindingContext = new ModelBindingContext() { ModelName = "foo", ValueProvider = dict};

    var target = new MagicBinder();

    Foo result = (Foo)target.BindModel(null, bindingContext);
}

public class Foo
{
    public int Number { get; set; }
    public int Test { get; set; }
}

Проблема?В MagicBinder привязкаContext.Model является нулевой.Если я попытаюсь установить его с помощью bindingContext.Model = new Foo ().Я получаю исключение, в котором говорится, что он устарел, и я должен установить ModelMetadata.

Итак, как мне создать ModelMetadata?Это даже не может быть осмеяно.

Ответы [ 2 ]

42 голосов
/ 18 февраля 2011

Попробуй так:

[TestMethod]
public void TestFooBinding()
{
    // arrange
    var formCollection = new NameValueCollection 
    {
        { "Number", "2" },
        { "Test", "12" },
    };

    var valueProvider = new NameValueCollectionValueProvider(formCollection, null);
    var metadata = ModelMetadataProviders.Current.GetMetadataForType(null, typeof(Foo));
    var bindingContext = new ModelBindingContext
    {
        ModelName = "",
        ValueProvider = valueProvider,
        ModelMetadata = metadata
    };
    var controllerContext = new ControllerContext();
    var sut = new MagicBinder();

    // act    
    Foo actual = (Foo)sut.BindModel(controllerContext, bindingContext);

    // assert
    // TODO:
}
2 голосов
/ 29 декабря 2017

Если кому-то из вас это нужно для работы с web-api, вы можете использовать этот метод, который будет проверять Get Requests, вы получите преимущество от использования встроенного провайдера:

Заполняет значения так, как они поступают из Интернета, вместо того, чтобы получать причудливые побочные эффекты от создания значений, которые поставщик может потенциально никогда не вернуть Null и т. Д.

using System;
using System.Globalization;
using System.Net.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Metadata.Providers;
using System.Web.Http.ModelBinding;
using System.Web.Http.ValueProviders.Providers;

namespace Apps.API.Web.Tests
{
    public class ModelBinderTestRule
    {
        //This URL is just a place holder for prefixing the query string
        public const string MOCK_URL = "http://localhost:8088/";

        public TModel BindModelFromGet<TBinder, TModel>(string modelName, string queryString, TBinder binder)
            where TBinder : IModelBinder
        {
            var httpControllerContext = new HttpControllerContext();
            httpControllerContext.Request = new HttpRequestMessage(HttpMethod.Get, MOCK_URL + queryString);
            var bindingContext = new ModelBindingContext();

            var dataProvider = new DataAnnotationsModelMetadataProvider();
            var modelMetadata = dataProvider.GetMetadataForType(null, typeof(TModel));

            var httpActionContext = new HttpActionContext();
            httpActionContext.ControllerContext = httpControllerContext;

            var provider = new QueryStringValueProvider(httpActionContext, CultureInfo.InvariantCulture);

            bindingContext.ModelMetadata = modelMetadata;
            bindingContext.ValueProvider = provider;
            bindingContext.ModelName = modelName;

            if (binder.BindModel(httpActionContext, bindingContext))
            {
                return (TModel)bindingContext.Model;
            }

            throw new Exception("Model was not bindable");
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...