Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock ModelState.IsValid using the Moq framework?

I'm checking ModelState.IsValid in my controller action method that creates an Employee like this:

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

I want to mock it in my unit test method using Moq Framework. I tried to mock it like this:

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

But this throws an exception in my unit test case. Can anyone help me out here?

like image 324
Mazen Avatar asked Sep 29 '10 14:09

Mazen


People also ask

What is Moq mocking framework?

Moq is a mocking framework built to facilitate the testing of components with dependencies. As shown earlier, dealing with dependencies could be cumbersome because it requires the creation of test doubles like fakes. Moq makes the creation of fakes redundant by using dynamically generated types.

What can be mocked with Moq?

Unit testing is a powerful way to ensure that your code works as intended. It's a great way to combat the common “works on my machine” problem. Using Moq, you can mock out dependencies and make sure that you are testing the code in isolation.

Can you mock a private method Moq?

Moq supports mocking protected methods. Changing the methods to protected , instead of private , would allow you to mock their implementation.

What does it mean if ModelState IsValid is false?

IsValid is false now. That's because an error exists; ModelState. IsValid is false if any of the properties submitted have any error messages attached to them. What all of this means is that by setting up the validation in this manner, we allow MVC to just work the way it was designed.


2 Answers

You don't need to mock it. If you already have a controller you can add a model state error when initializing your 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(); 
like image 110
Darin Dimitrov Avatar answered Sep 28 '22 23:09

Darin Dimitrov


The only issue I have with the solution above is that it doesn't actually test the model if I set attributes. I setup my controller this way.

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

The modelBinder object is the object that test the validity of the model. This way I can just set the values of the object and test it.

like image 30
uadrive Avatar answered Sep 29 '22 01:09

uadrive