If you’re too lazy or just plain impatient, you can find the source code here.
So one of the biggest pains in a place that doesn’t lend itself well to be in pain has been trying to unit test web forms like how MVC controllers can be. Before 4.0, this was an aggrevation at the least. Something in between stubbing one’s toe and getting only chocolate icecrfeam when you ask for a @*&*ing swirl. Serious, how hard is it to pull the swirl lever? Really.
Anyways, so there are certain things in .net web forms that were pretty difficult to hande/mock/get around for testing. Let’s take session for instance. Session is a sealed class with a non public constructor. To make things more interesting, the Page class only has a get for the Session property. Now you could go through a lot of hell, mostly reflection, to get aroud this, but who wants to do that? Personally I gave web forms the ole one finger salute, but being that I am working with web forms again… yeah had to find a way to get around this. The answer? Stems from dynamic.
Basically what I had to do is create a class that has a Session property that is dynamic, and then replace the old Session call with a class that calls a property named Session. The effect to the code, as far as the immediate code behind is concerned, is just this simple adding of the class before the Session call. Far as the code to do this, it’s fairly easy too.
First I started with an interface since using an interface will help later if I need to mock.
This is the bread and butter. Basically we have a container that will hold the session object. Making the property dynamic allows it to be set to anything. All I have to worry about is that whatever I set it to has the functionality used by Session. This is started by implementing the interface fo use on the site:
And then one for use with testing:
How are these used? Well if we take a base page:
So what this does is holds two constructors; One for use by .Net when it runs the site and one for the test class when it is testing the page functionality. The second is a way to stop all the stuff that happens in the Page class constructor when it’s time to unit test this [explitive]. This might look familiar to people who have used things such as Dependency Injection with MVC to help with Controller testing. If not, the idea is simple. It basically just gives the Page the test handler we need it to use when testing. If we aren’t testing, then we let it just use the default handler.
You might wonder why I didn’t instantiate the live version in the constructor, and the answer is: Session isn’t ready to be used at constructor time when doing the normal web site thing. Therefore, it will be set the first time the SessionHandler property is called. If it’s a test, well then it’s fine to set it in the constructor since it is bypassing the normal web site… thing.
The unit test looks something like this:
As you can see, a test version of the handler is created and the Session object is replaced with a Dictionary since that’s what Session is… well it has more to it but the most used feature is the key/value match and it happens to be the only part of Session I show in this example.
Since there is the second, test only, constructor on the page, we don’t have to worry about any asp.net stuff getting in the way when instantiating the page. The page will look like this:
As it can be see, the replacement of the Session call with SessionHandler.Session allows the features of Session but also the testability it lacked for so long. It’s true that if you want to use other features of Session, if there are any and I can’t remember, you’ll have to just add them to the test version so they can be called at test time. I can’t do everything for you.