Comment simuler ModelState.IsValid en utilisant le framework Moq?

Je vérifie ModelState.IsValid dans ma méthode d’action de contrôleur qui crée un employé comme ceci:

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

Je veux me moquer de moi dans ma méthode de test unitaire en utilisant Moq Framework. J’ai essayé de me moquer comme ça:

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

Mais cela jette une exception dans mon test élémentaire. Est-ce que quelqu’un pourrait m’aider?

Vous n’avez pas besoin de vous moquer de lui. Si vous avez déjà un contrôleur, vous pouvez append une erreur d’état du modèle lors de l’initialisation de votre test:

 // 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(); 

Le seul problème que j’ai avec la solution ci-dessus est qu’il ne teste pas réellement le modèle si je définis des atsortingbuts. Je configure mon contrôleur de cette façon.

 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; } 

L’object modelBinder est l’object qui teste la validité du modèle. De cette façon, je peux simplement définir les valeurs de l’object et le tester.

La réponse d’uradrive m’a pris une partie du chemin, mais il y avait encore des lacunes. Sans aucune donnée dans l’entrée du new NameValueCollectionValueProvider() , le classeur de modèle liera le contrôleur à un modèle vide, pas à l’object de model .

C’est bien, il suffit de sérialiser votre modèle en tant que NameValueCollection , puis de le transmettre au constructeur NameValueCollectionValueProvider . Pas tout à fait. Malheureusement, cela n’a pas fonctionné dans mon cas, car mon modèle contient une collection et le NameValueCollectionValueProvider ne joue pas bien avec les collections.

Le JsonValueProviderFactory vient à la rescousse ici, cependant. Il peut être utilisé par DefaultModelBinder tant que vous spécifiez un type de contenu "application/json ” et que vous transmettez votre object JSON sérialisé au stream d’entrée de votre requête (notez que, comme ce stream d’entrée est un stream de mémoire, vous pouvez le laisser indisponible, car un stream de mémoire ne conserve aucune ressource externe):

 protected void BindModel(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(Controller controller, TModel viewModel) { var controllerContext = A.Fake(); 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; }