Unit Testing Highly-Dependent Classes (Stubbing Classes such as System.Web.UI.Page)

After Jetbrains’ recent releases of DotCover and Resharper 6, along with a mostly isolated set of libraries, I forced myself to completely cover the code. I started out with a fairly TDD set of libraries, which allow me to have some classes prepopulated based on contextual information from the System.Web.UI.Page object that will serve as the destination for communication between two pages.

To start out, I had several classes with their own unique responsibilities, and then one base page (which had a generic type constraint) that allowed for the automatic population of the object in the page.

public ReceivingPageBase<T> : System.Web.UI.Page
where T : class, IPagePopulatableObject, new()
{
public T RecievedObject {get;set;}
protected Override void OnPreLoad(EventArgs e)
{
//attempt to load the object, persist in viewstate;
//if postback, load it from viewstate instead.
}
}
public ReportingInformation : IPagePopulatableObject
{ //some properties, implementation of IPagePopulatableObject }

Now the tricky part. As I went to write tests, and kept analyzing code coverage, I was also reading through The Art of Unit Testing by Roy Osherove. The book’s very well paced, and a fairly light read. It’s pretty easily explained stubbing and mocking, which have eluded me for a bit of time. I had used constructor injection for my repositories and stubbed them out so that my tests were non-db-dependant, and got my overall coverage up to about 85%.

As an aside, I had run into a closing-brace bug with DotCover itself that was tricky to workaround (see my next post for some details on that particular gem).

As I went to write tests against the remaining bit of code (the base page shown in the code sample above), I had tons of trouble writing a stub that would essentially be a fake page. Oh how easy it would be if only I could tag System.Web.UI with an interface… but alas, it’s in a framework library and out of my control.

So I slept for a couple days on that particular issue, doing some research, when I came across one of Martin Fowler’s solutions to this particular issue… using a design pattern known as Passive View in order to wrap the page. The real system can use a concrete class that directly maps and wraps System.Web.UI.Page, while the tests can use a stub that simulates page context information. Let’s jump to code to see how it works (note the last image in the Passive View link was the clearest application to this problem). First, we need to isolate the ReceivingPageBase<T> itself from the loading of the object. The ReceivingPageBase<T> class will be moved out of the library and close to the applications which consume it. In it’s place will be:

//In library:
public PagePopulatableObjectReciever<T>
where T:class, IPagePopulatableObject, new()
{
private readonly Page _page;
public T RecievedObject {get;set;}
public PagePopulatableObjectReciever(Page page)
{
_page = page;
Received = DoLoadObject();
}
private T DoLoadObject()
{
//attempt to load the object from _page, 
//persist in _page.viewstate;
//if postback, load it from _page.viewstate instead.
}
}
//In application:
public AppSpecificRecievingPageBase<T> : System.Web.UI.Page
where T : class, IPagePopulatableObject, new()
{
public T RecievedObject {get;set;}
protected Override void OnPreLoad(EventArgs e)
{
//attempt to load the object, persist in viewstate;
//if postback, load it from viewstate instead.
}
}

Note that this only gets us halfway there. We’ve split apart the page from the receiving, so now the page is relatively ‘dumb’ (read: decoupled; SRP is good!). But this still couples the ObjectReciever to the System.Web.UI.Page, where we want to use some stub instead. Well, it’s time to apply the PassiveView pattern. Create the Passive View of System.Web.UI.Page, with an interface and a concrete.

//1. Create the passive view interface
public interface IStatefulPage
{
StateBag ViewState {get;}
bool IsPostBack {get;}
NameValueCollection QueryString {get;}
}
//2. Make the application base page conform
public AppSpecificRecievingPageBase<T> : 
System.Web.UI.Page, IStatefulPage
where T : class, IPagePopulatableObject, new()
{
public T RecievedObject {get;set;}
protected Override void OnPreLoad(EventArgs e)
{
//attempt to load the object, persist in viewstate;
//if postback, load it from viewstate instead.
}
//explicit interface declaration
//needed to avoid conflict with 
//existing ViewState variable
StateBag IStatefulPage.ViewState
{
get {return ViewState;}
}
public NameValueCollection QueryString
{
get { return Request.QueryString;}
}
//IsPostback is 'free'; 
//signature already conforms.
}
//3. Replace the ObjectReciever's page with IStatefulPage.
public PagePopulatableObjectReciever<T>
where T:class, IPagePopulatableObject, new()
{
private readonly IStatefulPage _page;
public T RecievedObject {get;set;}
public PagePopulatableObjectReciever(IStatefulPage page)
{
_page = page;
Recieved DoLoadObject();
}
private T DoLoadObject()
{
//attempt to load the object from _page, 
//persist in _page.viewstate;
//if postback, load it from _page.viewstate instead.
}
}

Now at this point, we’ve broken the coupling of object receiving from the Page object. This is fantastic… the last prep step is to create our stub to use for tests. Obviously depending on your tests, your behavior may vary, but I wanted to add in a sample set of data to receive, and have a working state to store it in for postback, giving me the following stub:

public class StubObjectReceivingPageWithValidObject :
IStatefulPage
{
public StubObjectReceivingPageWithValidObject
(string objectKey)
{
_queryString.Add("MASTERKEY",objectKey);
IsPostBack = false;
}
private readonly StateBag
_viewState = new StateBag();
public StateBag ViewState
{
get { return _viewState;}
}
public bool IsPostBack {get;set;}
private readonly NameValueCollection
_queryString = new 
NameValueCollection();
public NameValueCollection QueryString
{
get { return _queryString;}
}
}

Now I can use that stub for testing, and it will simulate page and context without the need for any sort of test web server, or ‘real’ building of a web page and context information.

What have we learned? Well, wrapping any framework class in an interface can be done through the use of wrapper objects, essentially making a Passive View. Our stub page winds up being a Test Double (aka Imposter) which allows us to test without using any true Page instances. That’s all good.

What’s the downside to doing this? Shallow interfaces for one. I made one that had ViewState, IsPostBack, and QueryString, because I knew those were what I needed to know. If some other class has other parts of the page, I could have either expanded IStatefulPage, or created another Passive View interface. Perhaps these can get out of control if you have too many. Also another downside is that I’m using trainwreck notation (see number 5 here from “Uncle” Bob Martin’s seminal Clean Code) for things like mapping IStatefulPage’s QueryString to Request.QueryString. I can live with that, at least for the present.

All of this leads to increasing testability, and speed of testing. It’s important to keep test speeds high in order to keep your team running them often.

Posted on 8/19/2011 8:00:00 AM by Jason Nadal

Permalink | Comments |

Categories: asp.net | codeQuality | patterns | tdd | unitTesting

Tags: , , ,

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Membership Providers and Password Hashing -- be careful!

While recreating some boilerplate code that winds up getting created for every set of apps -- including a membership provider, roles provider, etc, I initially went right for setting hashAlgorithmType based right on the enum.

More info about membership properties here.

This enum only gives three values -- MD5, SHA1, and None. The problem here is that both of those algorithms have been proven broken for some time (hopefully ASP.NET 4.0 will resolve this!). The answer of course is to use something with a little more difficulty to it... say by using SHA512Managed() and a salt. This is just another one of those times when setting values to canned possibles can be a dangerous move. This is especially true with authentication / encryption.

 

Posted on 4/8/2010 6:43:00 AM by Jason Nadal

Permalink | Comments |

Categories: asp.net | development | security

Tags: , ,

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Improved Paging

I don't know how everyone feels about pagers, and specifically about the GridView, but it's sometimes the quickest way to solve a problem. I had worked on an isolated area of an application where GridView seemed like a good fit, although the built-in paging mechanism never quite seems to fit the bill.

So I did some research, and came across this blog post by Francisco Santos, Jr., giving a very clean-looking paging system. The best parts about it are the instant notification of just how many pages are being returned, coupled with a dropdown to choose which page to actually go to. The blog post is flawed in that it never mentioned that the ImageButtons in the PagerTemplate needed to be bound to the Paginate method he declares (sometimes the best part about a blog post is the comments!), but other than thatt, the approach is good.

Also cool on his blog is a post about a script outline add-in that allows you to use Document Outline with Javascript. It's written for VS2005, so I can't guarantee it'll work for 2008.

Posted on 10/27/2008 6:39:00 PM by Jason Nadal

Permalink | Comments |

Categories: asp.net | development

Tags: ,

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

ASP.NET performance tuning: HttpModules can be dangerous!

I decided to give Jetbrains' dotTrace a try, since I had a clear need to do some performance tuning on an in-design application at work. The symptoms were down to a line in the data access area that was calling out to a service to get data that would be the same for every user. This data would change fairly unoften, and only when a new client was signed and set up.

So with that in mind, I expected to see a poor performance from the service call, and have something to measure against when I implemented a cache for the results.

What I was not expecting to find was a 2.5 second delay on every page! It turns out that a third party upload control, an HttpModule that shall remain nameless, was causing lengthy delays while reading its config properties on every ASP.NET request. The HttpModule was implemented in the main web.config for the application, resulting in even the public pages, and parts of the application that would get no gain from having the upload control's module loaded were taking the performance hit.

The simple solution was just to move the module's declaration into a lower Web.Config, in the folders where the upload was actually taking place. The moral of the story is that a) HttpModules can be dangerous (this was a situation that would've been so much better suited for an HttpHandler), and b) performance tuning tools should be a no-brainer for a developer, and can even help coding practices for things that would never normally have crossed your mind!

Lastly, dotTrace seems extremely easy to use, and I'd highly recommend it.

Posted on 10/1/2008 7:48:00 PM by Jason Nadal

Permalink | Comments |

Categories: development | asp.net

Tags:

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5