DataAnnotations and MetadataType fails in unit tests
This post describes how to solve the problem that model validation will not work for ASP.NET MVC 2 when testing a model that uses DataAnnotations and MetadataType to describe for its validation.
First of all,
ModelState.IsValid is always
true, since the function that sets
it to false for invalid models is never executed by the unit tests. This will cause
controllers to behave incorrectly while testing.
MetadataType bindings are ignored during the test execution. This
causes the validation within it to be ignored as well, which in turn will cause
the model to be valid although an object is invalid.
I’m currently writing tests for a Create controller method. I use NUnit and have
an Entity Framework 4 Entity Model with entities, e.g. an
To enable model validation during unit tests, I create a partial
in the same namespace as the entity and a
MetadataType class that handles validation
for the class. This is described here.
EmployeeController has a
Create function that takes an employee and tries
to save it. If the
ModelState is invalid, the controller returns the Create view
and displays the error. However, if it’s valid, it creates the employee and returns
the employee list.
Easy enough, right? However, when I started to write tests for these classes, it
turned out that
ModelState.IsValid was always true, even if the tests received
invalid employees. Turns out that model validation is not triggered by the tests.
Trigger model validation within a test
To trigger model validation within a test, you can use the
Controller extension method. Just rewrite this test code:
var result = controller.Create(new Employee());
to instead look like this:
var result = controller.CallWithModelValidation(c => c.Create(new Employee()), new Employee());
This makes the unit test properly trigger model validation, which means that the test suite can now test that the controller behaves correctly for invalid models.
The only problem with this approach, is that the model validation doesn’t catch
errors in the model, even if the model is invalid. After some testing, I noticed
that this does only occur for partial objects that use
MetadataType to specify
model validation. Turns out that
MetadataType is ignored by the unit tests.
Before we proceed, make sure to note that classes that describe their validation
attributes directly are correctly validated. The next part is only relevant when
Register MetadataType connections before testing
MetadataType problem and how
InstallForThisAssembly can help.
This method must be placed within the same assembly as the model, not in the test
project. I place it in a
ControllerExtensions class file and call it at the
This will not work if you move the extension to another project, so make sure to have it in the correct project.
Run it before your tests, and everything should work.