3

I am starting to learn Unit testing in MVC4.

This is my controller.

public class AccountController : Controller
{
    public ActionResult Register(User user)
    {
        if (ModelState.IsValid)
        {
            return View("RegistrationSuccessful");                
        }
        return View("Register");
    }
}

And this is the test.

public class AccountControllerTests
{
    [TestMethod]
    public void invalid_registration_details_should_show_registration_form_again()
    {
        var controller = new AccountController();
        var user = new User();
        user.Name = null;
        var result = controller.Register(user) as ViewResult;
        Assert.AreEqual("Register", result.ViewName);
    }
}

And this is the model.

public class User
{
    [Required]
    public string Name { get; set; }
}

When I call controller.Register(user) I think the model binder does not come in to picture as I am instantiating the controller myself and not through the framework. So I think ModelState.IsValid will be true by default.

How do I test this? How can model validation be triggered in unit tests?

4 Answers 4

2

You can also achieve by below approach to validate model. In my case below ProjectViewModel is my model. In below scenario, I didn't set Description property to validate if validation working.

[TestMethod]
[ExpectedException(typeof(ValidationException), "Please enter description.")]
public void Create_Project_Empty_Description()
{
    ProjectViewModel model = new ProjectViewModel
    {
        ProjectID = 3,
        Name = "Test Project",
        StartDate = DateTime.Now.Date,
        EndDate = DateTime.Now.AddMonths(-1),
        States = new List<ProjectStateViewModel> { new ProjectStateViewModel { StateName = "Pending" } }
    };

    ValidationContext contex = new ValidationContext(model);
    Validator.ValidateObject(model, contex);
}
Sign up to request clarification or add additional context in comments.

1 Comment

Here's another variation on this. stackoverflow.com/questions/2167811/…
2

Since there is no logic in the controller other than checking if ModelState.IsValid==true, I think you might just want a unit test for your model.

First, your model. I would change it to look something like this:

public class User : IValidatableObject
{
    public string Name { get; set; }
    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        // I personally add all my validation here instead of adding [Required] to specific properties, this helps me know all of my validation is in this one place and add other complex validations if needed
        // This code here determines if ModelState.IsValid 
        var retVal = new List<ValidationResult>();
        if (string.IsNullOrEmpty(this.Name))
        {
            retVal.Add(new ValidationResult("Name is Empty", new List<string> { "Name" }));
        }
        return retVal;
    }
}

Second, the unit test. I would write tests where I would expect a specific error message for a specific property. In this example I am giving a null value and expecting the error message "Name is Empty" for the property "Name":

    [TestMethod]
    public void NullOrEmptyName()
    {
        var model = new YourProject.Models.Account.User { Name= null };
        var validationContext = new ValidationContext(model);
        var validation = model.Validate(validationContext).ToList();
        Assert.AreEqual(validation.Count(x => x.ErrorMessage == "Name is empty" && x.MemberNames.Single() == "Name"), 1);
    }

Comments

0

I'm not sure if it is possible to trigger model validation but I know how to test it.

Try this code:

    [TestClass]
    public class AccountControllerTests
    {
        [TestMethod]
        public void invalid_registration_details_should_show_registration_form_again()
        {
            // arrange
            var controller = new AccountController();
            controller.ViewData.ModelState.AddModelError("Key", "ErrorMessage");

            // act
            var result = controller.Register(new User()) as ViewResult;

            // assert
            Assert.AreEqual("Register", result.ViewName);
        }

        [TestMethod]
        public void valid_registration_details_should_show_registration_successful_page()
        {
            // arrange
            var controller = new AccountController();

            // act
            var result = controller.Register(new User()) as ViewResult;

            // assert
            Assert.AreEqual("RegistrationSuccessful", result.ViewName);
        }
    }

Comments

0

You can do it by forcing it to validate your model by calling following from test. For my tests, i created a TestHelper class inside which mocked this method and added ModelState.AddModelError() for specific conditions.

TryValidateModel(model);// will do the task

May be you need to mock the ControllerContext as well for this.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.