RSS Feed

Asp.Net Mvc regular expression attribute Testing–DateTime validation problem

 

Context

When developing simple validation logic in Asp.Net Mvc you can use the built in validators. One of them is the RegularExpression Validator. I had a simple scenario with a property of  DateTime type called StartDate. Validation format (yyyy-mm-dd). It should be a simple task , but details are always messy.

I created a simple pattern and tested it with various examples in one of the Regex Editors.

 [RegularExpression(@”^(19|20)\d\d([- /.])(0[1-9]|1[012])\2(0[1-9]|[12][0-9]|3[01])$”)]
 public DateTime StartDate { get; set; }
 

To check if this solution works , two unit tests were created. First implementation of tests used the Regex class , but then I found out that you can use  Attribute classes inside your code. I changed tests and used the RegularExpressionAttribute class inside test. Those tests are better because , with Regex our , we are checking if regex pattern is correct. With Attribute class used inside the test , we are testing actual scenario that is happening inside our app .

Here are the tests.

    [TestFixture]
    class CalendarEventRegExpTests
    {
        private string regex = @”^(19|20)(\d\d)[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])$”;

        [Test]
        public void Should_match()
        {
            var dateTime = “2011-10-1”;
            var attribute = new RegularExpressionAttribute(regex);
            Assert.IsTrue(attribute.IsValid(dateTime));
        }

SUCCESS

        [Test]
        public void Should_not_match()
        {
            var dateTime = “01-10-2001”;
            var attribute = new RegularExpressionAttribute(regex);
            Assert.IsFalse(attribute.IsValid(dateTime));
        }

    }

SUCCESS
 

Yey green light, They passed so it’s working ! I tested the app and … validation was always incorrect . First thought , my pattern is incorrect. But , it is working inside RegEx Editor so I it has to be correct.

Problem

It seems that when DateTime object is passed to the RegExpAttribute , something weird is happening and validation fails. I have simulated this scenario with simple test.

        [Test]
        public void Should_match()
        {
            var dateTime = new DateTime(2011,11,10);
            var attribute = new RegularExpressionAttribute(regex);
            Assert.IsTrue(attribute.IsValid(dateTime));
        }

FAIL

 

Maybe it’s the problem with the type of the object. This test converts DateTime object to string fail.

        [Test]
        public void Should_match()
        {
            var dateTime = new DateTime(2011,10,10);
            var attribute = new RegularExpressionAttribute(regex);
            Assert.IsTrue(attribute.IsValid(dateTime.ToString()));
        }

FAIL 

 

Then I realized that .ToString() , method by default creates string including the hh-mm-ss. In my scenario those parameters were initialized with zeros My simple regex pattern wont match this string. Correctly formatted string passes the Test.

        [Test]
        public void Should_match()
        {
            var dateTime = new DateTime(2011,10,10);
            var attribute = new RegularExpressionAttribute(regex);
            Assert.IsTrue(attribute.IsValid(dateTime.ToString(“yyyy-MM-dd”)));
        }

SUCCESS
 

It’s time to look inside the RegularExpressionAttribute.  Let me “Reflect” or “DotPeek”  that for you.

Here is the code inside the class.

    public override bool IsValid(object value)
    {
      this.SetupRegex();
     string input = Convert.ToString(value, (IFormatProvider) CultureInfo.CurrentCulture);
      if (string.IsNullOrEmpty(input))
      {
        return true;
      }
      else
      {
        Match match = this.Regex.Match(input);
        if (match.Success && match.Index == 0)
          return match.Length == input.Length;
        else
          return false;
      }
    }

The Highlighted part is the problem. .IsValid() method uses default.ToString(). DateTime is parsed to the string with hh-mm-ss and that’s the root of the problem.

Solution

There is a simple solution to this problem. You just need to attach DisplayFormat.

DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = “{0:yyyy-MM-dd}”)]

 

Lessons Learned

– “green light” in test doesn’t mean that your code is working .

– create tests on “real” data

– try simulate environment and context as much as possible. To many assumptions and your test isn’t testing real scenario. In my case , I  used the string inside test when my app used DateTime object.

Advertisements


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s