如何使用Moq框架来模拟ModelState.IsValid?

我在我的控制器操作方法中检查ModelState.IsValid ,创build一个Employee像这样:

 [HttpPost] public virtual ActionResult Create(EmployeeForm employeeForm) { if (this.ModelState.IsValid) { IEmployee employee = this._uiFactoryInstance.Map(employeeForm); employee.Save(); } // Etc. } 

我想用我的unit testing方法使用Moq框架来嘲笑它。 我试图嘲笑它是这样的:

 var modelState = new Mock<ModelStateDictionary>(); modelState.Setup(m => m.IsValid).Returns(true); 

但是在我的unit testing用例中抛出了一个exception。 有人可以帮我从这里出去吗?

你不需要嘲笑它。 如果你已经有一个控制器,你可以在初始化你的testing时添加一个模型状态错误:

 // arrange _controllerUnderTest.ModelState.AddModelError("key", "error message"); // act // Now call the controller action and it will // enter the (!ModelState.IsValid) condition var actual = _controllerUnderTest.Index(); 

上面解决scheme唯一的问题是,如果我设置属性,它实际上不testing模型。 我这样设置我的控制器。

 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对象是testing模型有效性的对象。 这样我就可以设置对象的值并对其进行testing。

uadrive的答案把我的一部分,但还是有一些差距。 没有任何数据input到new NameValueCollectionValueProvider() ,模型联编程序会将控制器绑定到空模型,而不是model对象。

这很好 – 只需将您的模型作为NameValueCollection序列化,然后将其传递给NameValueCollectionValueProvider构造函数。 那么,不完全。 不幸的是,它不起作用,因为我的模型包含一个集合,并且NameValueCollectionValueProvider不能很好地与集合一起玩。

JsonValueProviderFactory在这里来救援,虽然。 只要你指定了一个"application/json ”的内容types,并将你的序列化的JSON对象传递给你的请求的inputstream,就可以被DefaultModelBinder使用(请注意,因为这个inputstream是一个内存stream,不存在,因为内存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; }