DataAnnotations and MetadataType fails in unit tests

This post describes how to solve the problem that model validation will not work for ASP.NET MVC2 (.NET 4.0) when testing a model that uses DataAnnotations and MetadataType to describe for its validation.

First of all, ModelState.IsValid is always true, since the functionality that sets it to false if the model is invalid is never executed during the test cycle. This will cause your controllers to behave incorrectly during your tests.

Second, MetadataType binding is ignored during the test cycle as well. This will cause the validation within it to be ignored as well, which in turn will cause the model to be valid although an object is invalid.

My situation

I am currently writing tests for a Create method in one of my controllers. I use NUnit as test framework. I have an EF4 Entity Model, in which I have a couple of entities. For instance, I have an Employee entity with FirstName, LastName and Ssn properties.

To enable model validation, I create a partial Employee class in the same namespace as the EF4 entity model, then create a MetadataType class, which handles validation for the class. This approach is fully described in this blog post.

In my EmployeeController, I have a Create method that takes an employee and tries to save it. If ModelState.IsValid is false, the controller returns the Create view again and displays the errors. If the model is valid, however, I create the employee and return the employee list.

Easy enough. Well, when I started to write tests, I realized that ModelState.IsValid is always true, even if I provide the method with an invalid employee. Turns out that model validation is not triggered by the unit test.

Trigger model validation within a test

This blog post describes the ModelState.IsValid problem and provides a slick solution – the CallWithModelValidation Controller extension method.

I added this extension method to my MVC2 project and used it instead of calling Create, as such:

   Before:
   var result = controller.Create(new Employee());

   After:
   var result = controller.CallWithModelValidation(c => c.Create(new Employee()), new Employee());

And sure enough, this causes the test to trigger model validation. The only problem is that the model validation does not catch any errors within the model, even if the model is invalid.

After some fiddling, I noticed that this error only occurs for partial objects that uses MetadataType to specify model validation. A class that describes its validation attributes directly is validated correctly.

Turns out that the MetadataType class is ignored within test context. Thus, the model is always considered to be valid.

Register MetadataType connections before testing

This blog post describes the MetadataType problem and provides a slick solution – the InstallForThisAssembly method.

This method must be placed within the same assembly as the model, in other words not the test project. I placed it in a ControllerExtensions class file and call it at the beginning of CallWithModelValidation. This works, but will not work if you move the extension to another project.

Run it before your tests, and everything will work “as it should”.

Hope this helps.

Advertisements