Showing posts with label validation. Show all posts
Showing posts with label validation. Show all posts

Thursday, August 22, 2013

Creating data validation unit test

Creating a unit test is pretty simple for a method, but when your business/POCO objects are relying on DataAnnotation for validation, how do you make sure that they are implemented and tested? Obviously, one can create all the classes run the test from the UI and check whether one can enter invalid data. Is there another way of doing this instead of waiting to test them from the UI? If we are doing TDD, can we build the test first?

For example, let's say we have this class "Person", which requires that both first name and last name to be required, but middle name is optional.
public class Person
{
    [Required]
    public string FirstName { get; set; } 

    public string MiddleName { get; set; } 

    [Required]
    public string LastName { get; set; } 
}
There are several ways to create tests for this class - the first one is to check whether the property is decorated with the RequiredAttribute.
[TestMethod]
public void Person_FirstName_IsRequired()
{
    // arrange
    var propertyInfo = typeof(Person).GetProperty("FirstName");
 
    // act
    var attribute = propertyInfo.GetCustomAttributes(typeof(RequiredAttribute)).Cast().FirstOrDefault();
 
    // assert
    Assert.IsNotNull(attribute);
}
Or another way is by testing the validation itself.
[TestMethod]
public void Person_FirstName_IsRequired()
{
    // arrange
    var person = new Person();
    var context = new ValidationContext(person, null, null);
    var validationResults = new List();

    // act
    var isValid = Validator.TryValidateObject(person, context, validationResults);

    // assert
    Assert.IsTrue(validationResults.Any(e => e.ErrorMessage == "The FirstName field is required"));
}
-- read more and comment ...

Monday, March 25, 2013

Creating Validation Adapter for Validation Attribute

If your project is rather big, often you would like your validation to reside on the business layer instead of on the UI layer. So for example, using our previous code sample, it would make perfect sense if the custom attribute code resides in your business layer project (instead of on the UI project). BUT, to enable client validation (here for example), implementing IClientValidatable is required and IClientValidatable is within the System.Web.Mvc namespace. This means that your business layer needs to reference System.Web.Mvc. But why would you want to do that - referencing a UI related reference in your business layer project?

When we look at the built-in validator (such as RequiredAttribute), how did they do this? If we look at the documentation, it is within System.ComponentModel.DataAnnotations.ValidationAttribute namespace and deriving from System.Object - there is no dependency to System.Web.Mvc at all. We can use that validation attribute in WinForm, Silverlight, WebForm, WPF, etc.


There is no magic - the ASP.NET guys simply built a validation adapter for it in the System.Web.Mvc namespace. In this post, I am going to show you how to build one for our MagicNumber validator.

So let's clarify on our namespacing issue - in our business layer, let's call that MyApp.Library project (namespace: MyApp.Library), which includes MyClass.cs (namespace: MyApp.Library or MyApp.Library.MyClass to be complete) and our custom validation attribute MagicNumberAttribute.cs (namespace: MyApp.Library or MyApp.Library.MagicNumberAttribute to be complete).

Here is the code for MyApp class:
   public class MyClass {
      // ... more code
      [MagicNumber(ErrorMessage = "Sum is not correct")]
      public int MyData { get; set; }
      // ... more code
   }
Here is our code for the custom validation attribute in MagicNumberAttribute.cs:
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
sealed public class MagicNumberAttribute : ValidationAttribute {
   // constructor to accept the comparison property name
   public MagicNumberAttribute(string thirtySevenProperty) : base() {
      if (thirtySevenProperty == null) {
         throw new ArgumentNullException("thirtySevenProperty");
      }
      ThirtySevenProperty= thirtySevenProperty;
   }

   // property to store the comparison field name
   public string ThirtySevenProperty{ get; private set; }

   protected override ValidationResult IsValid(object value, ValidationContext validationContext) {
      // get property info of the "ThirtySevenProperty"
      PropertyInfo thirtySevenPropertyInfo = validationContext.ObjectType.GetProperty(ThirtySevenProperty);

      // check if that property exists / valid
      if (thirtySevenPropertyInfo == null) {
         return new ValidationResult(String.Format(CultureInfo.CurrentCulture, "UNKNOWN PROPERTY", ThirtySevenProperty));
      }

      // get the value of the property
      object thirtySevenPropertyValue = thirtySevenPropertyInfo.GetValue(validationContext.ObjectInstance, null);

      // do comparison and return validation result with error if not equal
      if (!Equals(value, thirtySevenPropertyValue)) {
         return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
      }

      // return null if everything is ok
      return null;
   }
}
We'll call our ASP.NET MVC project to be MyApp.UI.Mvc (namespace: MyApp.UI.Mvc). Here is our javascript from the previous post, we'll reuse it, put it in a js file:
   jQuery.validator.unobtrusive.adapters.addSingleVal("magicnumber", "other");

   jQuery.validator.addMethod("magicnumber", function (val, element, other) {
      var modelPrefix = element.name.substr(0, element.name.lastIndexOf(".") + 1)
      var otherVal = $("[name=" + modelPrefix + other + "]").val();
      if (val && otherVal) {
        return val == otherVal;
      }
      return true;
   );
So now, instead of implementing IClientValidatable, we will be creating a validation adapter. We will put this in a file in our MyApp.UI.Mvc project, let's name it "MagicNumberAttributeAdapter.cs". The code is simple:
public class MagicNumberAttributeAdapter : DataAnnotationsModelValidator
{
   public MagicNumberAttributeAdapter(ModelMetadata metadata, ControllerContext context, MagicNumberAttribute attribute)
       : base(metadata, context, attribute)
   {
   }

   public override IEnumerable GetClientValidationRules()
   {
      var rule = new ModelClientValidationRule
      {
          ErrorMessage = this.ErrorMessage,
          ValidationType = "magicnumber",
      };
      rule.ValidationParameters.Add("other", this.Attribute.ThirtySevenProperty);
      yield return rule;
   }
}
To make the connection between the adapter and the validation attribute itself, we need to let MVC know about it - so we need to register it inside the global.asax.cs file:
DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(MagicNumberAttribute), typeof(MagicNumberAttributeAdapter));
Once all those are setup, our custom validator will fire on the client-side (as well as server-side), we have clear separation of concern - where the business layer does not reference the UI as dependency, and our custom validation attribute is also reusable. Awesome!

Additional reading:
-- read more and comment ...

Tuesday, March 12, 2013

Custom Validation Attribute - Client Side Enabled!

In previous posts, I outlined how to make a custom validation attribute - including a more complex one that depends on another property. Both of those validators are working - but they are working on the server-side. So if you have an ASP.NET MVC web application, the validation will fire after it gets to the server side within your controller. Ideally, we want to do client-side validation as well - so that the form does not need to POST if the data is not valid. How do we do that?

We can make custom javascript, query the fields manually and check for conditions - but this code will be disconnected from the custom validator that we created. Doing custom javascript also means that it will be so specific that the likelihood of being reusable is very very small.

Also, as we have seen with the built-in validators that shipped with ASP.NET MVC, they seem to just work - no custom javascript needed per field or manual client-side validation. When a property or a field is decorated with the correct attribute and client-side validation is enabled in the web.config, then boom - it just works. How can we make our validator to behave in similar manner?


One way to do this is by implementing IClientValidatable in your custom validator. Implementing this interface means we must implement a method called "GetClientValidationRules". This method is what basically will become a connector for our validator to the client-side. The property decorated with our custom validation attribute will then outputting flags that will indicate that it should be evaluated during client-side validation. In this method as well we need to provide additional information to properly evaluate the validity of the property on the client-side - mostly a (javascript) method name to be called during validation and some parameters needed to evaluate property within that method. When we do this, this is the updated validator class will look like:
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
sealed public class MagicNumberAttribute : ValidationAttribute, IClientValidatable {
   // constructor to accept the comparison property name
   public MagicNumberAttribute(string thirtySevenProperty) : base() {
      if (thirtySevenProperty == null) {
         throw new ArgumentNullException("thirtySevenProperty");
      }
      ThirtySevenProperty= thirtySevenProperty;
   }

   // property to store the comparison field name
   public string ThirtySevenProperty{ get; private set; }

   protected override ValidationResult IsValid(object value, ValidationContext validationContext) {
      // get property info of the "ThirtySevenProperty"
      PropertyInfo thirtySevenPropertyInfo = validationContext.ObjectType.GetProperty(ThirtySevenProperty);

      // check if that property exists / valid
      if (thirtySevenPropertyInfo == null) {
         return new ValidationResult(String.Format(CultureInfo.CurrentCulture, "UNKNOWN PROPERTY", ThirtySevenProperty));
      }

      // get the value of the property
      object thirtySevenPropertyValue = thirtySevenPropertyInfo.GetValue(validationContext.ObjectInstance, null);

      // do comparison and return validation result with error if not equal
      if (!Equals(value, thirtySevenPropertyValue)) {
         return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
      }

      // return null if everything is ok
      return null;
   }

   public IEnumerable<ModelClientValidationRule$gt; GetClientValidationRules(ModelMetadata metadata, ControllerContext context) {
      yield return new ModelClientValidationEqualToRule(this.ErrorMessage, OtherProperty);        
   }
}
In the code above, I am reusing an existing validation rule "ModelClientValidationEqualToRule" which will connect with "equalto" jQuery client-validator. This is a pre-existing rule, so at this point, we can just run this and it should work - no more code needed.

In the next post, I will go over on how to return our own custom ModelClientValidationRule and how to create a corresponding javascript client-side validator.

Additional reading:
-- read more and comment ...

Friday, March 8, 2013

Creating Custom Validation Attribute With Dependency To Other Property

In the last post, I went through the steps to make a custom validation attribute - if you missed it, check it out here: Creating Custom Validation Attribute. Now let's say we want to make our validator to look up on the value "37" from another property in our class (instead of hard-coding it). How do we do that? With the help of reflection, we can do that quite easily.

Here is our modified class:
public class MyClass {
   // ... more code
   [MagicNumber("ThirtySeven", ErrorMessage = "Sum is not correct")]
   public int MyData { get; set; }
   // ... more code
   public int ThirtySeven {
      get { return 37; }
   }
   // ... more code
}

In our new custom validator, we override a different IsValid method (the original one is commented out):
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
sealed public class MagicNumberAttribute : ValidationAttribute {
   // constructor to accept the comparison property name
   public MagicNumberAttribute(string thirtySevenProperty) : base() {
      if (thirtySevenProperty == null) {
         throw new ArgumentNullException("thirtySevenProperty");
      }
      ThirtySevenProperty= thirtySevenProperty;
   }

   // property to store the comparison field name
   public string ThirtySevenProperty{ get; private set; }

   // public override bool IsValid(object value) {
   //    var num = int.Parse(value.ToString());
   //    return num == 37;
   // }

   protected override ValidationResult IsValid(object value, ValidationContext validationContext) {
      // get property info of the "ThirtySevenProperty"
      PropertyInfo thirtySevenPropertyInfo = validationContext.ObjectType.GetProperty(ThirtySevenProperty);

      // check if that property exists / valid
      if (thirtySevenPropertyInfo == null) {
         return new ValidationResult(String.Format(CultureInfo.CurrentCulture, "UNKNOWN PROPERTY", ThirtySevenProperty));
      }

      // get the value of the property
      object thirtySevenPropertyValue = thirtySevenPropertyInfo.GetValue(validationContext.ObjectInstance, null);

      // do comparison and return validation result with error if not equal
      if (!Equals(value, thirtySevenPropertyValue)) {
         return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
      }

      // return null if everything is ok
      return null;
   }
}

That's it!
Additional reading:
-- read more and comment ...