Go Back

Unit test asp.net with your own MVC pattern

Making ASP.Net unit testable

 

So, previously I took a stab at trying to explain (in detail) how to get to some unit testable asp.net code from your legacy code. I failed because instead of explaining the goal, I was explaining the step by step of how to get there.

 

Let’s set this up for everyone first in a few different ways.

 

First, let’s talk about what currently exists in your legacy asp.net code and why it becomes impossible for you to test it without opening yourself up for a lot of dangerous changes!

 

For those who are familiar with UML this should be pretty straightforward. Imagine you have “AccountDetailsPage” in your project and it has the following class structure:

image002.gif

 

The difficult part about your code is probably that inside BindData() you’re making some calls to web services, pulling in some account object, binding fields to the labels, maybe storing some stuff in view state or session state, maybe checking against some conditions. Then in FilterGridByDate() you’re maybe iterating through a collection of transactions, removing some that don’t have the right date or getting a new list of transactions from the back end.

 

There’s three different types of behavior going on here… at least!

 

Let’s identify them.

First, there’s the view data/behavior that’s happening… OnLoad(), OnInit(), Session[], ViewState[], all of those labels, the data grid.

 

Second there’s some specific domain behavior happening, such as the loading of an account object, loading of transaction history objects.

 

Then, there’s some non-technology specific UI logic that is happening here, such as Filtering by date.

 

But lastly, and the thing that is probably most difficult to decide what to do when trying to unit test is the operations that are sharing data between those different responsibilities: When we copy stuff from a domain object into the ui objects during binding, when we iterate through domain objects with some UI logic, and when we load something from session or view state into some UI logic or into some business logic.

 

Let’s take a look at the different areas of concern first and put some names to them.

 

  1. Page Objects: technology specific (ASP.NET)
  2. UI Logic : Non-tech specific (Sorting, filtering, presentation changes)
  3. Business Logic : specific business data being operated on in a way that the business decided. Business rules!

 

Note: ignore that I’m assuming your business doesn’t dictate your presentation J because they do! (which is why we have to validate against the presentation separated from the technology)

 

Consider the MVC pattern now:

http://en.wikipedia.org/wiki/Model-view-controller

 

Your page Object would become your view, your UI Logic would become your controller, and your business object would become your Model.

 

How would this play out with our class above and how do we break the joint dependencies?

 

First of all, let’s create the 3 types we know of for the behavior we know about:

image004.gif

 

Now, let’s address the question “How do I test the UI and Business logic without testing asp.net?”

 

First, the controller is the UI logic so we have to call controller logic from our events/overrides in the page. Let’s look at how we would do that. Pretty simple actually, because it’s OK for our page to depend on the controller (because we won’t be unit testing the page, we can just have a reference to the controller right inside the page!)

 

That would look like this then:

image006.gif

 

Ok, wait a sec though… how am I suppose to set the text on the page INSIDE THE CONTROLLER???

 

Ok that’s a little more challenging, because we cannot pass the page reference into the controller or then our controller is dependent on the page class and we’re untestable again. What we have to do is resort to using an interface so that we can create a fake page in testing (or a mock). That would look something like this:

image008.gif

 

Effectively, we are going to send a page instance into the controller via the interface reference so that it’s decoupled. Then when we unit test the controller logic, we just create a Fake object that Implements the interface and use ‘sensing’ to see if the right values are going into the view. It would look like this in the test harness:

image010.gif

 

 

Facebook DZone It! Digg It! StumbleUpon Technorati Del.icio.us NewsVine Reddit Blinklist Furl it!

Post a comment!
  1. Formatting options