Entity
Framework 4.1(EF4.1) provides in-built support for defining the validation
constraints in model through Data Annotation attributes and Fluent API. It’s
one of the cool features provided by EF4.1 that enables the developers to define
validation rules of the model in an easy and more maintainable way. In addition
to that MVC3 framework makes use of these validation model and supports both
client and server side validation without writing any code!
I’m
in the early days of practising Test Driven Development (TDD). Fortunately I
have got an opportunity to implement TDD in my current assignment. I feel I am
much oriented and focused towards the solution while using TDD. Also it makes
me to critique my design and the way I do the coding. I would like to be a
better programmer and looking forward to improve myself and hence TDD suits me
more. Learning TDD and practising TDD is totally different! Yes, in theory it
is very easy to read and understand TDD. But when you practise it, you will
encounter many more interesting things about TDD and in fact it’s where you can
actually learn TDD.
Okay,
how to do TDD with Controller's responsibility in the context of Model validation in MVC3. Well, it is easy but
we should understand and find out what exactly we want to test and the way to
test them. Many articles and blog posts suggest doing it through the controller.
Is it really a good approach to test the model validation through
controller? Kindly think of it for a
moment. I feel it is not a right way to deal this stuff.
Let me explain
it through a small example. Consider an Employee model which has two
properties Name and Age and an EmployeeController responsible for doing
CRUD on Employee Model. What is the responsibility of EmployeeController when creating a new Employee data? It should check whether the posted employee model is valid or not, if it is valid add to the database else return the view with the validation errors. MVC3 framework makes life easy by automatically validating the Posted model and set the IsValid Property of the ModelState and also add validation errors to the model. Hence controller's job is very easy as follows
Corresponding TestCases:
- When creating a new employee, if the passed employee data is valid, it should be added to the database
- When creating a new employee, if the passsed employee data is InValid, it should not add to the database and show the view with validation errors.
The first unit test will be as following:
This unit test makes use of the following fake Database implementation.
To keep this blog post simple, I am not showcasing the TDD steps which I have done here and the EmployeeController Code would be as follows.
Employee Controller makes use of an InMemory Database (Simplest option!!) which implements the IRepository interface.
I have done all the wire ups to make the first unit test pass. (Pardon me! For the sake of simplicity of this blog post I've violated TDD rules. Hope you can infer the TDD steps from the coding samples). Its time to move to the next unit test and here comes a bottleneck.
You may wonder what it is that. There comes a feature of ASP.NET MVC 3 framework. During HTTP post action the framework validates the employee model and sets the EmployeeController's Property ModelState.IsValid to true or false. It occurs only during HTTP post. In our unit test code we are actually calling the action methods of the controller and not making any HTTP post. So, the ModalState is always true whenever we call the action methods of a controller from a unit testing code.
In our second test case, we need to setup a controller in such a way that its ModelState property is InValid. We can do this by adding a ModelError to the ModelState property of the EmployeeController. Infact it is what MVC3 framework is doing under the hood when making HTTP post.
Hurrah! Thats it !!
Now we Test drived the controller's responsibility in the context of model validation. In my next blog post I'd showcase how to the test drive the model validation itself.
Nice post...very useful
ReplyDeletethats just my opinion that validation code should not be attribute based because it is not TDD friendly. isn't it better to use FluentValidations or any similar library to create validators and test them in a TDD way (isolated).
ReplyDeleteWhere as in your code you are testing two things in one test i.e. controller, and model.
whats your opinion on that?
@Adeel
ReplyDeleteThe blog posts objective is to test drive the controllers responsibility in the context of model validation. As you said, we shouldn't test two things in a single test. In fact it is the objective of this blog post series. Here i'm testing only the controller's behavior alone. The unit tests just simulate a invalid model and test its equivalent controller's behavior. In my next blog post I'd cover how to test drive model validation.
Very Nice...
ReplyDeleteWhy don't you give it a thought to write some blogs about TDD steps as well.
Thanks White,
DeleteWill surely do.
why would you need to test the out of the box validation in a unit test? Seems like a decent acceptance test, but not sure of the value here. Thoughts?
ReplyDeleteGood catch.. It is a valid candidate for acceptance test. This blogpost just mention the technique through a unit test. You can leverage this easily in an acceptance test.
Delete