Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TDD: What is best practice to test DataAnnotations in ASP.NET MVC 3?

I'm participating in a project using ASP.NET MVC 3 and DataAnnotations. We have DataAnnotations in ViewModels classes.

How do you write unit tests for these validations?

ViewModel example:

public class AchievementVM
{
    [Required(ErrorMessage = "The title field is required.")]
    [StringLength(100, ErrorMessage = "Title must be 100 characters or less.")]
    public string Title { get; set; }
}

Thanks!

like image 208
Ygor Thomaz Avatar asked Aug 06 '12 20:08

Ygor Thomaz


People also ask

How is TDD implemented in ASP.NET MVC?

Under Installed Templates, open the Visual C# node, select Data, and then select the ADO.NET Entity Data Model template. In the Name box enter, ContactModel and then click Add. The Entity Data Model Wizard window is displayed. Under What should the model contain, select Generate from database and then click Next.

What is DataAnnotations MVC?

DataAnnotations is used to configure your model classes, which will highlight the most commonly needed configurations. DataAnnotations are also understood by a number of . NET applications, such as ASP.NET MVC, which allows these applications to leverage the same annotations for client-side validations.

What are commonly used tool for unit testing in ASP.NET MVC?

To write unit tests, you need a unit testing framework. Some popular ones are MSTest that comes with Visual Studio, NUnit, and XUnit. There are others. I will use NUnit in my examples.


2 Answers

Since those annotations are very declarative, there is little sense in writing unit tests which just check (with reflection) that the methods are annotated - the tests would just be duplicating the production code. And that would still leave the possibility that the annotations are not being used the way that the framework expects them to be used (maybe they are the wrong annotations, they are in the wrong place, or they are missing some additional configuration).

Thus a meaningful test would not be a unit test, but an integration test which makes sure that the system is detecting the annotations correctly. To keep the speed reasonable, try to make those integration tests as focused as possible, by instantiating as little of the framework as possible (which requires deep knowledge of the framework - RTFS). If nothing else, an end-to-end test could check the correct use of the annotations by parsing the HTML and checking that the validation errors are shown when invalid data is entered into the fields.

It should be necessary to write just a couple of integration/end-to-end tests to make sure that validation has been enabled. There shouldn't be need to test each and every field, when they all work the same way.

like image 23
Esko Luontola Avatar answered Sep 19 '22 12:09

Esko Luontola


The .NET framework comes with a Validator class which can exercise your validation logic in isolation. The code to test could look like this:

var achievement = new AchievementVM();
var context = new ValidationContext(achievement, 
    serviceProvider: null, items: null);
var results = new List<ValidationResult>();

var isValid = Validator.TryValidateObject(achievement, context, results, true);

Assert.IsTrue(results.Any(vr => vr.ErrorMessage == "The title field is required."));

achievement.Title = "Really really long title that violates "
    + "the range constraint and should not be accepted as "
    + "valid input if this has been done correctly.";

Validator.TryValidateObject(achievement, context, results, true);

Assert.IsTrue(results.Any(vr => vr.ErrorMessage == "Title must be 100 characters or less."));

No need for custom utilities to search for the existance of attributes. The Validator class does the work for you and populates a ValidationResult collection the same as the MVC infrastructure.

A good writeup on this method can be found on K. Scott Allen's blog.

like image 86
Phil Patterson Avatar answered Sep 23 '22 12:09

Phil Patterson