Pages

I've migrated my blog

Thanks for visiting my blog. I am no longer maintaining this and I've migrated the blog to my personal domain . If you would like to follow my blog kindly use my new RSS feed

Sunday, March 4, 2012

Unit Testing Html Helpers in ASP.NET MVC3–The Cleaner Way

 

Would you like if your unit test have an assertion like this ?

image

IMHO having a unit test assertion like this with a long magical string value would become a maintenance problem with additional logic being added. It breaks with even minor changes like “adding an extra whitespace” though it is logically correct(Browsers ignores the whitespaces while rendering html)!. It is harder to debug to!!

How can we get rid of this long string assertion ? Is there any better way to do assertion against this long magical string ejected from a HtmlHelper ? One thing which strikes on my mind when I come across this problem is why don’t we parse the string as an xml and assert against the xml element instead. It might appear like laborious at the first sight, but by making use of XElement and extension methods we can easily do that. In the blog post we are going to see how can we implement this in a more cleaner way.

Okay.. Enough texts.. Its time to see some code!!

The first step is to convert the “html string” returned by the html helper to XElement. Generally most of the helpers returns MvcHtmlString, So, we can easily achieve this by writing an extension method called “ToXElement” on MvcHtmlString.

image   

That’s it! All set to redefine the way custom html helpers are being tested.

Fine, Let us see it in action. We will start with a handy HtmlHelper method called “Button” which would render a “Html button tag” and here is the test to assert it.

image

The first test uses the ToXElement extension method and assert against the XElement’s properties whereas the second test uses the “magical string with tags added” to do the assertion. Now you may feel what’s wrong with this guy the second test look clean to me, why he is making fuss about it. Yes you are correct, the second one looks clean. But it appears to be clean as the requirement in hand is very simple.

IMHO the custom html helpers that we are building in our real world application won’t be as simple as having a button tag with just plain caption in it.

Fine, lets see the real world. Voice from your team lead

Hey! the Button HtmlHelper you designed has did a tremendous job. Can you make a small change on it so that it would generate a button with a class attribute having the value ‘appbutton’ by default. We need it because it make the button styling consistent with rest of our application ”

Let us implement the feature by starting with the test for it

image

Now tell me is the second test clean ? I don’t think so. The generate html string is bit long now also having double quotes inside double quotes makes it hard to read. At the same time the first test remains robust and clean.

Still not convinced, okay just go up and see the very first test that we have wrote to test the button caption. Do you think the hard way test with the “long magical string” still pass ??

It would fail

Why ?? Here is the error message

image

Now what would you do, if you decided to persist with the “long magical string”, then your action would be editing the test as below

image

Nice job. Now tell me what is the difference between this one and the below one

image

Apart from the test method name everything is same. Is the test clean ? Is the test clearly saying what it is trying to assert ? What would happen if we got the requirement to add one more attribute or even more? Think !!

But at the same time the tests which written using XElement assertion would remain healthy and their test method name mean what it is testing

image

I leave it you to decide which one is cleaner.

Summary

Here is the implementation of “Button HtmlHelper” that we unit tested so far

image

My humble request to the readers of this blog post, please take care of your “Unit tests” and give some more importance to it. An hour spent upfront would save a day in future.  

“Beauty is in the eye of the beholder”, If you have a better idea to do the same, kindly leave a comment, I am open to learn from you.