Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ModelState.IsValid always true when testing Controller in Asp.Net MVC Web Api

I have tried to make this work and made many google/stackoverflow searches with no luck at all.

I have a simple Model:

public class MovieModel
{
    public string Id { get; set; }

    [Required]
    [StringLength(100)]
    public string Name { get; set; }
}

A method in the controller:

// POST: api/Movies
public IHttpActionResult Post([FromBody]MovieModel movieModel)
{
    if (ModelState.IsValid)
    {
        //Code
    }
}

And a test method (is an integration test, but the same would happen in unit tests):

[TestMethod]
public void MoviesController_Post_Without_Name()
{
    // Arrange
    var model = new MovieModel();
    model.Name = "";

    // Act
    var result = controller.Post(model);

    // Assert
    Assert.IsInstanceOfType(result, typeof(InvalidModelStateResult));
    Assert.AreEqual(6, controller.Get().Count());
}

Despite the fact that the model is clearly invalid it always evaluates the IsValid property to true.

I tried many approaches so far without success.

like image 966
André Baptista Avatar asked Jun 01 '16 01:06

André Baptista


People also ask

Why ModelState IsValid is false in MVC?

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.

How ModelState IsValid works in MVC?

ModelState. IsValid indicates if it was possible to bind the incoming values from the request to the model correctly and whether any explicitly specified validation rules were broken during the model binding process. In your example, the model that is being bound is of class type Encaissement .

What ModelState is IsValid validate?

IsValid property is checked and if the Model is valid, then the value if the ViewBag object is displayed using Razor syntax in ASP.Net MVC.

What is ModelState Clear () in MVC?

Clear() is required to display back your model object. If you are getting your Model from a form and you want to manipulate the data that came from the client form and write it back to a view, you need to call ModelState. Clear() to clean the ModelState values.


Video Answer


2 Answers

Thanks to this site, I found out the solution:

private void SimulateValidation(object model)
{
    // mimic the behaviour of the model binder which is responsible for Validating the Model
    var validationContext = new ValidationContext(model, null, null);
    var validationResults = new List<ValidationResult>();
    Validator.TryValidateObject(model, validationContext, validationResults, true);
    foreach (var validationResult in validationResults)
    {
        this.controller.ModelState.AddModelError(validationResult.MemberNames.First(), validationResult.ErrorMessage);
    }
}

And including one line in the test method like this:

public void MoviesController_Post_Without_Name()
{
    // Arrange
    var model = new MovieModel();
    model.Name = "";

    // Act
    SimulateValidation(model);
    var result = controller.Post(model);

    // Assert
    Assert.IsInstanceOfType(result, typeof(InvalidModelStateResult));
    Assert.AreEqual(6, controller.Get().Count());
}

Hope that helps someone, it would have saved me some hours hunting the web.

like image 159
André Baptista Avatar answered Sep 28 '22 09:09

André Baptista


Your solution probably works, but a better way is using ApiController.Validate method.

public void MoviesController_Post_Without_Name()
{
    // Arrange
    var model = new MovieModel();
    model.Name = "";

    // Act
    controller.Validate(model);   //<---- use the built-in method
    var result = controller.Post(model);

    // Assert
    Assert.IsInstanceOfType(result, typeof(InvalidModelStateResult));
    Assert.AreEqual(6, controller.Get().Count());
}
like image 38
Cheng Chen Avatar answered Sep 28 '22 11:09

Cheng Chen