Я проверяю ModelState.IsValid
свой метод действия контроллера, который создает такого сотрудника:
[HttpPost]
public virtual ActionResult Create(EmployeeForm employeeForm)
{
if (this.ModelState.IsValid)
{
IEmployee employee = this._uiFactoryInstance.Map(employeeForm);
employee.Save();
}
// Etc.
}
Я хочу поиздеваться над этим в моем методе модульного тестирования с использованием Moq Framework. Я пытался издеваться над этим вот так:
var modelState = new Mock<ModelStateDictionary>();
modelState.Setup(m => m.IsValid).Returns(true);
Но это вызывает исключение в моем модульном тесте. Может кто-нибудь помочь мне здесь?
c#
asp.net-mvc
unit-testing
mocking
moq
Mazen
источник
источник
Единственная проблема, с которой я столкнулся с приведенным выше решением, заключается в том, что оно фактически не тестирует модель, если я устанавливаю атрибуты. Я настроил свой контроллер таким образом.
private HomeController GenerateController(object model) { HomeController controller = new HomeController() { RoleService = new MockRoleService(), MembershipService = new MockMembershipService() }; MvcMockHelpers.SetFakeAuthenticatedControllerContext(controller); // bind errors modelstate to the controller var modelBinder = new ModelBindingContext() { ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, model.GetType()), ValueProvider = new NameValueCollectionValueProvider(new NameValueCollection(), CultureInfo.InvariantCulture) }; var binder = new DefaultModelBinder().BindModel(new ControllerContext(), modelBinder); controller.ModelState.Clear(); controller.ModelState.Merge(modelBinder.ModelState); return controller; }
Объект modelBinder - это объект, который проверяет достоверность модели. Таким образом, я могу просто установить значения объекта и протестировать его.
источник
Ответ uadrive взял меня на часть пути, но все еще были некоторые пробелы. Без каких-либо данных во входных данных
new NameValueCollectionValueProvider()
связыватель модели привяжет контроллер к пустой модели, а не кmodel
объекту.Это нормально - просто сериализуйте свою модель как объект
NameValueCollection
, а затем передайте его вNameValueCollectionValueProvider
конструктор. Не совсем так. К сожалению, в моем случае это не сработало, потому что моя модель содержит коллекцию, аNameValueCollectionValueProvider
она плохо работает с коллекциями.Однако
JsonValueProviderFactory
здесь на помощь приходит. Его можно использовать до техDefaultModelBinder
пор, пока вы укажете тип содержимого"application/json
"и передадите свой сериализованный объект JSON во входной поток вашего запроса (обратите внимание, поскольку этот входной поток является потоком памяти, можно оставить его нераспределенным, как память stream не привязан ни к каким внешним ресурсам):protected void BindModel<TModel>(Controller controller, TModel viewModel) { var controllerContext = SetUpControllerContext(controller, viewModel); var bindingContext = new ModelBindingContext { ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => viewModel, typeof(TModel)), ValueProvider = new JsonValueProviderFactory().GetValueProvider(controllerContext) }; new DefaultModelBinder().BindModel(controller.ControllerContext, bindingContext); controller.ModelState.Clear(); controller.ModelState.Merge(bindingContext.ModelState); } private static ControllerContext SetUpControllerContext<TModel>(Controller controller, TModel viewModel) { var controllerContext = A.Fake<ControllerContext>(); controller.ControllerContext = controllerContext; var json = new JavaScriptSerializer().Serialize(viewModel); A.CallTo(() => controllerContext.Controller).Returns(controller); A.CallTo(() => controllerContext.HttpContext.Request.InputStream).Returns(new MemoryStream(Encoding.UTF8.GetBytes(json))); A.CallTo(() => controllerContext.HttpContext.Request.ContentType).Returns("application/json"); return controllerContext; }
источник