Unit Testing Data Validation with MVC Unit Testing Data Validation with MVC

You've added some data validation and you want to test it out in action. The data validation can be standard data annotations, custom data attributes, or data validation implemented via an IValidatableObject. This article will explore how to leverage the ValidationContext to execute and assert the test results.


The ValidationContext

Unit testing data validation can be accomplished by creating a ValidationContext in conjunction with the Validator helper class. To demonstrate how this is accomplished, I will use the ValidationModel class I created in the Removing Data Validation from MVC Controllers. As you may recall this class contained an IValidatableObject that ensured if the boolean FixedQuantity was true, the MaxQuantity property must be null.

Setting up your Unit Test Project

To begin, a new unit test project is required. If you do not already have one in your project, right-click your solution and select Add -> New Project. On the left hand-side select Test. This will provide the option to create a new Unit Test project. Once selected, provide a meaningful and complete the project creation.

The ValidationContext class resides in the System.ComponentModel.DataAnnotations namespace; a reference to this class must be added to your unit testing project. Right-click the project and select Add -> Reference. Under assemblies, find the DataAnnotations and include in your project.

At this point everything is setup and ready to test. The following code example tests that a ValidationException is thrown when the ValidationModel class property FixedQuantity is true and MaxQuantity contains a value.


using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using RedirectWithModel.Models;
using System.ComponentModel.DataAnnotations;
namespace UnitTestProject1
{
[TestClass]
public class ValidationModelTests
{
[TestMethod]
[ExpectedException(typeof(ValidationException))]
public void FixedQuantityAndMaxQuantityIsInvalid()
{
var model = new ValidationModel {
FixedQuantity = true,
MaxQuantity = 1
};
var validationContext = new ValidationContext(model);
Validator.ValidateObject(model, validationContext);
}
}
}

The test method FixedQuantityAndMaxQuantityIsInvalid is attributed with the ExpectedException attribute looking for a ValidationException. The test method passes if the Validator.ValidateObject throws this exception; otherwise, the test will fail.

That's it, more tests can be created to validate other expected failure or success scenarios.

Replacing ExpectedException with ValidationException

Before finishing this post, I'm not a big fan of completely trusting the ExpectedException attribute. If your model contains multiple validation rules, this test does not ensure the expected exception is thrown. The next code example updates the previous validation test to perform a try/catch of the ValidationException. Inside the catch, the exception message is then asserted with the expected value, thus allowing us to be more certain the correct exception is being thrown.


using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using RedirectWithModel.Models;
using System.ComponentModel.DataAnnotations;
namespace UnitTestProject1
{
[TestClass]
public class ValidationModelTests
{
[TestMethod]
public void FixedQuantityAndMaxQuantityIsInvalid()
{
var model = new ValidationModel
{
FixedQuantity = true,
MaxQuantity = 1
};
ExecuteValidation(model, "A max quantity should not be specified when FixedQuantity is true");
}
private void ExecuteValidation(object model, string exceptionMessage)
{
try
{
var contex = new ValidationContext(model);
Validator.ValidateObject(model, contex);
}
catch (ValidationException exc)
{
Assert.AreEqual(exceptionMessage, exc.Message);
return;
}
Assert.Fail("Exception of type {0} should be thrown.", typeof(ValidationException));
}
}
}

After the ValidationModel is instantiated a new private function ExecuteValidation is called with the model and the expected exception message. I've created the private function as this seems like a nice reusable function when we have more than a single test method to assert. At the end of the function, if the catch method is not called (meaning the expected exception was not thrown), the test is forcibly failed via the Assert.Fail function.

Happy unit testing!

Published on May 11, 2015

Tags: validation | ASP.NET MVC and Web API Tutorial | Testing | ivalidatableobject | validationcontext

Related Posts

Did you enjoy this article? If you did here are some more articles that I thought you will enjoy as they are very similar to the article that you just finished reading.

Tutorials

Learn how to code in HTML, CSS, JavaScript, Python, Ruby, PHP, Java, C#, SQL, and more.

No matter the programming language you're looking to learn, I've hopefully compiled an incredible set of tutorials for you to learn; whether you are beginner or an expert, there is something for everyone to learn. Each topic I go in-depth and provide many examples throughout. I can't wait for you to dig in and improve your skillset with any of the tutorials below.