Create your own validator, TDD style
There are many validation frameworks out there but sometimes you need to build one your own. Let’s see how easy it is to build a simple validation framework in TDD style using functionalities in System.ComponentModel.DataAnnotations. This is a rather new assembly introduced in .NET Framework 3.5, mainly used to define metadata for ASP.NET Dynamic Data controls. We’re going to use the validation attributes containing in this assembly to validate our entities and models. There’s a contrib project on CodePlex which contains extentions to this assembly, if you need to use it further.
If you need to use a more powerful validation framework, it is advised to use CastleValidator, NHibernate Validator or other validation frameworks out there.
For starters, let’s create a project structure. We need two projects, one for the unit tests with reference to NUnit assemblies, and another project containing our actual validation framework. Remember to add a reference to System.ComponentModel.DataAnnotations assembly.
When developing in TDD style, you write a failing test before you write the actual code, then implement the functionality and make the test pass. After the test is passed, you can do some refactoring and continue the procedure from the start.
Other development styles that also use “some” kind of test or unit testing should not be thought of as TDD. The emphasis on TDD style is to write the test first, not after the implementation which is usually referred to as Test After style.
As the workflow suggests, let’s create our very first test. We want to test that the default validator instance can validate a model / entity. Here’s the test:
1 | [ ] |
As you can see, the test won’t even compile. We need to create missing classes and compile the solution first to make sure the test fails.
If you’re using Resharper addin, it can create almost every missing piece of the puzzle for you. To do this, click the missing class, interface or method, press ALT + Enter and select proper option from appearing menu. Resharper has a plugin called TDD Productivity plugin which helps you create missing types in referenced projects more easily.
Create a new interface in the project containing the implementation named “IValidator” and create the “Validate” method:
1 | public interface IValidator |
We need a default implementation of “IValidator”, to no surprise named “DefaultValidator”:
1 | public class DefaultValidator : IValidator |
The last remaining bit before we can compile the project is to create a Person class in our test project. This will be used as the object which we’ll try to validate:
1 | public class Person |
Let’s compile and run the test. The test will fail as expected. Since our test was over simplified, making it pass would be as easy as removing the exception:
1 | public void Validate<TEntity>(TEntity entity) |
Not much of an implementation. Let’s create a new test and change the Validate method to return a list of validation errors.
1 | [ ] |
The Arrange-Act-Assert (or AAA) is a readable test authoring pattern. Tests written in AAA are composed of 3 phases, Arrange in which test preconditions are defined, Act in which code under test is called and Assert in which results are inspected and failures are reported.
Once again, the code won’t compile. Let’s create missing pieces by changing the method signatures and adding ValidationError class.
1 | public interface IValidator |
Running the test, we’ll see that it won’t pass. Again, having “Doing the simplest thing possible” rule in mind, the implementation would be easy as:
1 | public IList<ValidationError> Validate<TEntity>(TEntity entity) |
An important TDD principal is to “Do the simplest thing possible that works”. This is closely related to YAGNI.
We should have two passing tests so far.
It is time to implement the actual validation method. Let’s start by creating a failing test:
1 | [ ] |
Before we run the test, let’s add missing properties to our Person class and decorate it with some validation attributes:
1 | public class Person |
Let’s run the test which will fail at this state. We’re going to use reflection to read the attributes on the model and see if the property values matches the decorating attribute. Combined with a LINQ query the implementation would be:
1 | public IList<ValidationError> Validate<TEntity>(TEntity entity) |
If you run the test, you still see one failing test, but that is actually another test that used to pass. So what went wrong? Check out the Assertion we made in test “Validate_Returns_ValidationErrors”. The problem is that we have not specified “Firstname” and “Lastname” property on Person instance, and we’re asserting that there won’t be any errors. To make this test pass again, we should pass a valid person instance. So let’s refactor this test into this:
1 | [ ] |
We’re almost done. There are some things we can still improve, like reading the error message from resource files instead of ErrorMessage property but I’m satisfied with this implementation so I won’t do it in this post. Finally, let’s see how good we did implementing this using TDD style by creating a coverage report.
Programming in TDD style has lots of “hidden” benefits too: The effort making things testable will lead you to decoupled components and by creating the tests first, you’ll have wider range of unit test compared to test-after style, hence better test coverage.
You can download the source code of this post here.