Sunday, July 3, 2011

Testing Asp.Net pages

Update - Arlo Belshee pointed out this applies better to "older" style asp programming.  If your pages don't resemble this pattern, please check out his response 

[Video at bottom of page]
Here is the strategy I’ve been using for unit testing Asp.Net pages. Aspx pages were almost intentionally made to be hard to test, so the result is as elegant as is possible for the given situation.

Note: If you want to test something that isn’t the “end result” of a web page, simply pull that logic into a separate class\method\dll and test it normally. This is for testing the final output of the page.


The Bottom Line: The following 1 line will test the AspxClass for a given scenario.

Approvals.ApproveAspPage(new AspxClass().TestMethod)

Architecture:

The Normal architecture when testing web pages is as follows


The strategy I've developed is very simular to this, but allows for better "test functionality" by adding a test method IN the aspx page, and then allowing a secret handshake, or backdoor to the aspx page to run that scenario.

Most Unit Tests for an asp.net page will take this form
1) Create an aspx page
2) Do some scenario
3) Verify the output of the page

When you do this in your testing, those 3 steps are going to  be split out across your code into 3 separate places:
1) The PageLoad event of your aspx page will handle the creation of the page and the redirect to the scenario of your choice (the TestMethod).
2) There will be a TestMethod which does the scenario part IN your aspx code behind page.
3) The Unit Test will Callout to the aspx page and verify the html output from the page. This actually starts the whole thing.

Simple Example:

Let’s say I wanted to test how an aspx page renders for a given company invoice:

Step 1) Write the Unit Test verification IN the Unit Test Class

Approvals.ApproveAspPage(new CompanyInvoiceView().TestSimpleInvoice);

it’s important to note that I’m not calling the method “TestSimpleInvoice” this is just a Delegate to that method. This is so I can “reflect” the http call needed to run the test.

Step 2) Write the Unit Test Setup IN the aspx page

public void TestSimpleInvoice()
{
    invoice = new Invoice{Name = “Test Company”}
    invoice.AddLineItem(“candy bar”, count = 2, cost = 0.50);
    invoice.AddLineItem(“soda”, count = 1, cost = 1.50);
    invoice.TaxRate = 0.10;
}


Step 3) Adding the “Test Diverter” IN the aspx page

Next, we need to intercept the call to go to the Test Method. This means adding the following code at the beginning of the Page_Load event

protected void Page_Load(object sender, EventArgs e)
{
    if (AspTestingUtils.DivertTestCall(this))
    {
        return;
    }


....
}


Step 4) Turn on the local test server and then run the tests.

Here’s a video of the whole thing in action...

1 comment:

Rob Murdoch said...

If your page's code behind is a partial class you might be able to put the secret test methods in a different file. If you everrode the system.web.page, you might be able to derive from that and put the utils call in the base class. Perhaps you could even compile them out of the final product with a conditional compilation variable.