Использование пользовательского ModelMetadataProvider в модульном тесте
Довольно новичок в MVC, так что, надеюсь, это простой вопрос.
Я написал собственный атрибут привязки, который требует доступа к httpContext
, Для того, чтобы ввести макет httpContext
во время юнит-тестов я написал InjectingMetadataProvider
что населяет Context
свойство на любом из моих пользовательских атрибутов.
Мне удалось заставить это работать в следующем тесте:
[TestMethod]
public void Marker_ShouldBind_Id()
{
// Arrange
var formCollection = new NameValueCollection
{
{ "id", "2" }
};
var context = new Mock<HttpContextBase>();
context.Setup(c => c.User).Returns((IPrincipal)null);
var metaProvider = new InjectingMetadataProvider(context.Object);
ModelMetadataProviders.Current = metaProvider; //why do I need this?
var bindingContext = new ModelBindingContext
{
ModelName = string.Empty,
ValueProvider = new NameValueCollectionValueProvider(formCollection, null),
ModelMetadata = metaProvider.GetMetadataForType(null, typeof(Marker)),
};
var binder = new DefaultModelBinder();
// Act
var marker = (Marker)binder.BindModel(new ControllerContext(), bindingContext);
// Assert
marker.Id.Should().Be(2);
}
Однако, если я закомментирую строку, которая устанавливает мой InjectingMetadataProvider
в ModelMetadataProviders.Current
тогда мой InjectingMetadataProvider.CreateMetadata()
Переопределение получает пустой список атрибутов, и поэтому тест не пройден, потому что мои пользовательские атрибуты не получают свой контекстный набор.
Почему мне нужно установить его Current
когда я использую это явно в любом случае? Я не хочу устанавливать статические вещи в своих тестах.
Возможно, я делаю что-то глупое, потому что в данный момент чувствую себя немного не в своей тарелке из-за того, что не знаком с фреймворком.
1 ответ
Внутри DefaultModelBinder новый контекст привязки создается при вызове BindComplexElementalModel. Обратите внимание, что он получает метаданные из ModelMetadataProviders.Current, а не от вашего поставщика метаданных пользовательской модели.
internal ModelBindingContext CreateComplexElementalModelBindingContext(ControllerContext controllerContext, ModelBindingContext bindingContext, object model) {
BindAttribute bindAttr = (BindAttribute)GetTypeDescriptor(controllerContext, bindingContext).GetAttributes()[typeof(BindAttribute)];
Predicate<string> newPropertyFilter = (bindAttr != null)
? propertyName => bindAttr.IsPropertyAllowed(propertyName) && bindingContext.PropertyFilter(propertyName)
: bindingContext.PropertyFilter;
ModelBindingContext newBindingContext = new ModelBindingContext() {
ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, bindingContext.ModelType),
ModelName = bindingContext.ModelName,
ModelState = bindingContext.ModelState,
PropertyFilter = newPropertyFilter,
ValueProvider = bindingContext.ValueProvider
};
return newBindingContext;
}