When I decided to write down a little class to manage a menu, I created a simple object that reads the menu data in xml, and transform it into a series of MenuItem object. The first thing I wanted to do is writing some test to verify that the logic is ok, but since my class uses Url.RouteUrl to build the url from the controller and action strings, testing becomes difficult, because it does not runs outside iis.
You can surely mock controller context in asp.net mvc, and there are a lot of good articles in the net dealing with this, but sometimes I prefer a simpler approach that I used a lot in classic webform asp.net applications. Since the class that contains the logic to format the menu needs only to access the UrlHelper class, I abstracted it with a simple interface.
This simple interface does not even contains all methods of the standard UrlHelper, but it is enough for me, I’ll add more methods when I’ll need them. Now my class can declare a dependency to this interface.
then create the real object that will be used in the site. It is a simple wrapper for the real UrlHelper
Now the controller that uses MasterLogic class can create instance with this simple code.
For testing purpose I created another class that implements the IUrlHelper interface.
It basically created url with a fixed rule, but the important thing that now I can test MasterLogic without worrying about someone changing routes, since I can inject my MyTestUrlHelper class into my MasterLogic class, here is a test.
You can complain that this is not mvc style of decoupling logic from the context, mvc has introduced the System.Web.Abstractions namespace for doing this, but I still prefer this old style solution, because it works perfectly even for webforms. In classic asp.net applications when I need to access Session, or querystring or other context related data, I prefer to abstract everything with interfaces, so I can test outside the pipeline of IIS with little problem. The conclusion is that: if you want your classes to be testable, you should abstract every dependency with an interface, and not declare dependency to any concrete class.
Tags: asp.net mvc