На основе KISS, высокосвязная и слабая связь , задает эти вопросы -
существует замечательная книга" Крупномасштабная Разработка программного обеспечения C++ ", это способствует базовым типам внешне, если можно избежать другого заголовочного файла / интерфейсная зависимость, необходимо попытаться.
Вместо передачи BlogPost
вы также можете объявить параметр действий как FormCollection
. Затем вы можете создать BlogPost
самостоятельно и вызвать UpdateModel (model, formCollection.ToValueProvider ());
.
Это запустит проверку для любого поля в FormCollection
.
[HttpPost]
public ActionResult Index(FormCollection form)
{
var b = new BlogPost();
TryUpdateModel(model, form.ToValueProvider());
if (ModelState.IsValid)
{
_blogService.Insert(b);
return (View("Success", b));
}
return View(b);
}
Просто убедитесь, что ваш тест добавляет нулевое значение для каждого поля в форме представлений, которое вы хотите оставить пустым.
Я обнаружил, что выполнение этого способа за счет нескольких дополнительных строк кода делает мои модульные тесты более похожими на способ вызова кода во время выполнения, что делает их более ценными. Также вы можете проверить, что происходит, когда кто-то вводит «abc» в элемент управления, привязанный к свойству int.
Когда вы вызываете метод homeController.Index в своем тесте, вы не используете какую-либо среду MVC, которая запускает проверку, поэтому ModelState.IsValid всегда будет истинным. В нашем коде мы вызываем вспомогательный метод Validate непосредственно в контроллере вместо использования внешней проверки. У меня не было большого опыта работы с DataAnnotations (мы используем NHibernate.Validators), возможно, кто-то еще может предложить руководство, как вызвать Validate из вашего контроллера.
Я использую ModelBinders в своих тестовых примерах, чтобы иметь возможность обновить значение model.IsValid.
var form = new FormCollection();
form.Add("Name", "0123456789012345678901234567890123456789");
var model = MvcModelBinder.BindModel<AddItemModel>(controller, form);
ViewResult result = (ViewResult)controller.Add(model);
С моим методом MvcModelBinder.BindModel следующим образом (в основном тот же код, который используется внутри инфраструктуры MVC):
public static TModel BindModel<TModel>(Controller controller, IValueProvider valueProvider) where TModel : class
{
IModelBinder binder = ModelBinders.Binders.GetBinder(typeof(TModel));
ModelBindingContext bindingContext = new ModelBindingContext()
{
FallbackToEmptyPrefix = true,
ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, typeof(TModel)),
ModelName = "NotUsedButNotNull",
ModelState = controller.ModelState,
PropertyFilter = (name => { return true; }),
ValueProvider = valueProvider
};
return (TModel)binder.BindModel(controller.ControllerContext, bindingContext);
}
У меня была такая же проблема, и, прочитав ответ и комментарий Полса, я стал искать способ вручную проверить модель представления.
Я нашел этот учебник , в котором объясняется, как вручную проверить ViewModel, использующий DataAnnotations. Фрагмент кода ключа будет ближе к концу сообщения.
Я немного изменил код - в учебнике 4-й параметр TryValidateObject опущен (validateAllProperties). Чтобы получить все аннотации для проверки, необходимо установить значение true.
Дополнительно я реорганизовал код в универсальный метод, чтобы упростить тестирование проверки ViewModel:
public static void ValidateViewModel<TViewModel, TController>(this TController controller, TViewModel viewModelToValidate)
where TController : ApiController
{
var validationContext = new ValidationContext(viewModelToValidate, null, null);
var validationResults = new List<ValidationResult>();
Validator.TryValidateObject(viewModelToValidate, validationContext, validationResults, true);
foreach (var validationResult in validationResults)
{
controller.ModelState.AddModelError(validationResult.MemberNames.FirstOrDefault() ?? string.Empty, validationResult.ErrorMessage);
}
}
До сих пор это работало для нас очень хорошо.