Testing the page object for an ASP.NET site

Using ASP.NET unit tests, you can test classes and methods that are part of an ASP.NET web site. This is often very similar to testing anything else, since you can use code generation on classes that are within the App_Code directory for the site. Unfortunately, it's not possible to generate tests for the page class itself (the one defined in the .aspx and .aspx.cs files for the page), due to differences in how Visual Studio handles these files. That doesn't mean you can't test it, though. The example below and following comments show how to access the current page for an ASP.NET unit test, call methods on it, and use its controls. Note that the attributes for ASP.NET unit tests are slightly different now than in Beta 2--if you're using that release, the test method will also require a [WebServerType(WebServerType.Iis)] attribute.

 
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.VisualStudio.TestTools.UnitTesting.Web;
 
[TestClass]
public class UnitTest1
{
    private TestContext testContextInstance;
 
    public TestContext TestContext
    {
        get { return testContextInstance; }
        set { testContextInstance = value; }
    }
    
    [TestMethod]
    [HostType("ASP.NET")]
    [UrlToTest("https://localhost/TestSite")]
    public void TestMethod1()
    {
        Page page = testContextInstance.RequestedPage;          //1
 
        Button button = (Button)page.FindControl("Button1");    //2
        Label label = (Label)page.FindControl("Label1");
 
        PrivateObject po = new PrivateObject(page);             //3
        po.Invoke("Button1_Click", button, EventArgs.Empty);
        Assert.AreEqual("Button1 clicked", label.Text);
    }
}

1. The Page object is available through the RequestedPage property of the TestContext object for the class. Since the actual type of the page is dynamically generated when the page is loaded, we can only provide this as an object of type Page, but it’s still possible to access members of the specific subclass of the page (see 3, below).

2. You can get the controls on the page using FindControl() or the Controls collection. Note that you may need to dig down a couple levels if some controls are within a container, as happens when you use master pages.

3. When you generate tests against classes in the App_Code directory, private accessors are created that allow you to reference those types and call their methods. As mentioned above, we can't generate code for the page class, so private accessors can't be created either. However, you can use PrivateObject to access members of the page that aren’t normally available through the Page object. In my example I use this to call Button1_Click(button, EventArgs.Empty), which is defined in default.aspx.cs.

Once you have the page object, you can use the standard Page methods and properties to work with it and its controls as you need. With a PrivateObject providing access to nonpublic members, you can essentially test the page just like you would any other class.

Kevin Cogger

SDET, Visual Studio Team System