Hans
Hans

Reputation: 467

Stubbing ASP.NET Page.Form for unit tests

Fo unit testing ASP.NET controls I need a stubbed Page.

I can create an ASP.NET Page object in my unit tests by subclassing System.Web.UI.Page. However, I cannot find a way to set Page.Form. Adding a form with attribute (runat,server) does not work. Overloading the form in my Subclass does not give the required functionality.

Context: I try to unit test some homemade ASP.NET controls. These control require Page and Page.Form not to be null.

Any suggestions?

Upvotes: 8

Views: 3454

Answers (3)

Steven
Steven

Reputation: 172835

Try defining an IPage and IForm interface that implement the needed methods and properties and create classes that implements those interfaces and wraps a Page or Form class. This way you can test the logic in those controls, without calling into the ASP.NET framework during unit testing.

UPDATE:

Overriding the page property will be brittle and is not advisable. Instead, you should try to minimize the amount of untestable code, by extracting logic in methods that don't depend on any ASP.NET specific (hard to test) parts. Take a look at the following example:

public class MyLabel : Label
{
    protected override override void RenderContents(HtmlTextWriter writer)
    {
        IPage page = new PageWrapper(this.Page);
        this.MethodToTest(page);

        base.RenderContents(writer);
    }

    internal void MethodToTest(IPage page)
    {
        // Work with IPage interface.
        if (page.IsPostBack)
        {
            this.Text = string.Empty;
        }
    }
}

By extracting the logic out of methods that are hard to test, you can call those extracted methods directly in your tests. For instance:

[TestMethod]
public void MethodToTest_ScenarioToTest_ExpectedBehavior()
{
    // Arrange
    var label = new MyLabel();

    var page = new TestPage()
    {
        IsPostBack = true
    };

    // Act
    label.MethodToTest(page);

    // Assert
    Assert.IsTrue(string.Empty, label.Text);
}

It would be even better if you would be able to extract the code under test to it's own class and call it from your WebControl. This is however, not always possible.

I hope this makes sense.

Upvotes: 3

Martin R-L
Martin R-L

Reputation: 4047

I had the same problem with ASP.NET a few years back, and we implemented Fowler's «Passive View» pattern, and managed to unit test all of the logic (and left the tests of the pretty dumb views to manual testing).

Upvotes: 0

D-Bar
D-Bar

Reputation: 185

What exactly are you trying to test? If what you are testing is not completely dependent on the page itself maybe you can avoid needing an instance of page entirely saving yourself a lot of heartache. Take a look at the following link:

http://xunitpatterns.com/Humble%20Object.html.

However, if what you are trying to test really depends on the page class wrap it with your own class that provides access methods to the data. Then turn that class into an interface to be used as a parameter to the method or to the constructor.

Example:

public testPageNull_shouldThrowArgumentNullException()
{
    PageWrappable nullPage = new MockPageWrappable();
    nullPage.GetPage().Return(null);

    CustomControl sut  = new CustomControl(nullPage);   

    Assert.Fail("Exception not thrown");
}

public interface PageWrappable
{
    //Gets Wrapped Page Instance
    WrappedPage GetPage();

    //GetSomethingFromTheForm
    String GetFormValue(String Key);
}

Upvotes: 1

Related Questions