16

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!

Ygor Thomaz
  • 507
  • 5
  • 14
  • 1
    What this data annotations do? Is it validation or something else? – Kirill Bestemyanov Aug 07 '12 at 06:10
  • It marks some component to be validated. A practical example of manual validation with data annotations: http://odetocode.com/blogs/scott/archive/2011/06/29/manual-validation-with-data-annotations.aspx – Ygor Thomaz Jul 30 '14 at 17:24

3 Answers3

17

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.

Matt Frear
  • 52,283
  • 12
  • 78
  • 86
Phil Patterson
  • 1,242
  • 15
  • 25
  • Great answer. This is the perfect way to unit test. I can verify that validation occurred without having to manually specify what is validating it. – Mike Bailey Mar 04 '13 at 17:01
  • 1
    I would recommend to `results.Clear()` collection before using it again in `TryValidationObject()`. – Daniel Kmak Jun 28 '14 at 16:50
4

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.

Esko Luontola
  • 73,184
  • 17
  • 117
  • 128
1

See here: Unit Testing ASP.NET DataAnnotations validation

Also, you can use reflection to see if a property of class has any necessary attribute or not.

Community
  • 1
  • 1
AD.Net
  • 13,352
  • 2
  • 28
  • 47