Ray
Ray

Reputation: 4108

ModelState.IsValid does not validate model

My Model class is as follow :

public class PostInputViewModel
    {
        [Required]
        [MinLength(1)]
        [MaxLength(125)]
        public string Title { get; set; }

        [Required]
        [AllowHtml]
        [Display(Name="Content")]
        public string Content { get; set; }
    }

and controller is as follow :

[HttpPost]
        public ActionResult Write(PostInputViewModel input)
        {
            if (!ModelState.IsValid)
                return View(input);

            var post = new Post
            {
                Title = input.Title,
                Content = input.Content,
                DateCreated = DateTime.Now,
                DateModified = DateTime.MaxValue,
            };

            dbContext.Posts.Add(post);
            dbContext.SaveChanges();

            return RedirectToAction("Index", "Home");
        }

When I run web application by clicking F5, and if I don't input title and content value, ModelState.IsValid is false, However if I test controller class with unit test case, ModelState.IsValid is always true. The test case is as follow :

[TestMethod]
        public void write_should_validate_model()
        {
            var input = new PostInputViewModel();
            input.Title = null;
            input.Content = null;
            var actionResult = controller.Write(input) as ViewResult;

            Assert.IsFalse(actionResult.ViewData.ModelState.IsValid);
        }

Am I missing something? Thanks in advance.

Upvotes: 2

Views: 7131

Answers (3)

Kevin M
Kevin M

Reputation: 1110

Validation actually happens before the Write method on your controller is called, which populates the ModelState property.

Your unit test isn't really testing the controller in my opinion (if that is in fact what you're trying to do).

A true controller test would look something like this:

        [TestMethod]
        public void write_should_validate_model()
        {
            controller.ModelState.AddModelError("Title", "Empty"); //These values don't really matter

            var actionResult = controller.Write(new PostInputViewModel()) as ViewResult;

            //Assert that the correct view was returned i.e. Not Home/Index
            //Assert that a new post has not been added to your Mock Repository                
        }

Upvotes: 4

Muhammad Hasan Khan
Muhammad Hasan Khan

Reputation: 35126

Validation of model doesn't happen in the Controller. It happens before the model is passed to the controller.

Notice the controller action is only 'testing' whether the model is valid. Who is validating the model in your test case? Nothing!

You can do the validation using Validator class of .NET however in that case you would be testing .NET validation. This is one of the common mistakes people make while writing unit tests. They test 3rd party code instead of their own.

If you really want to test that you have applied the correct validation attributes to the class then you can simply reflect your class and check for attributes on properties. This way you would be skipping the .NET validation layer and your test will only fail if you miss an attribute.

Upvotes: 4

Jacob
Jacob

Reputation: 78850

If you want to have your controller try to validate the model, you can call the TryValidateModel method before your assert:

controller.TryValidateModel(input);

But I agree that you'd really only be testing the validation attributes. It might be OK, though; it would validate that your model has the expected attributes applied.

Upvotes: 9

Related Questions