views:

81

answers:

1

We have developed a number of ASP.Net server controls and we need to test them. I want to instantiate a control, set some properties, call CreateChildControls and test the control-hierarchy.

I run into a number of problems:

  1. The controls rely on HttpContext
  2. CreateChildControls is private

Even adding a single child control to the controls collection calls the ResolveAdapter() method which relies on HttpContext.

How can I get around this?

p.s. I do not wish to test the controls on a page (!).

+1  A: 

It sounds a lot like you don't care about the actual rendering of the control at all, but rather the logic contained within the control. For that I would suggest that you have another problem besides the inability to test the control outside the HttpContext.

If the logic only pertains to the control, then you should trust the framework to do it's job, and drop the control on a page to see if it works properly. If the logic you are attempting to test is business logic, then you need to refactor.

Pull out the business logic into a seperate Project/Dll somewhere, and think about implementing a MVP pattern with your server control. You don't have to go with a big heavy framework like WCSF either. Conceptually you can implement this with little effort.

Create an interface that represents the values on your view:

public interface IOrderView
{
    Int32 ID{get; set;}
    String Name{get; set;}
    List<Item> Items {set;}
}

Once this is defined, you need a presenter that exercises this view:

public class OrderPresenter
{
    public IOrderView View {get; set;}

    public void InitializeView()
    {
        //Stuff that only happens when the page loads the first time

        //This is only for an example:
        var order = Orders.GetOrder(custId);

        View.ID = order.ID;
        View.Name = order.Name;
        View.Items = order.Items;
    }

    public void LoadView()
    {
        //Stuff that happens every page load
    }
}

Now your server control can implement this interface, and initialize itself with the OrderPresenter

public class OrderControl: Panel, IOrderView
{
    private OrderPresenter Presenter{get; set;}

    public OrderControl()
    {
        //Create new presenter and initialize View with reference
        // to ourselves
        Presenter = new OrderPresenter{View = this;}
    }

    protected override void OnLoad(EventArgs e)
    {
        if(Page.IsPostback)
        {
            _presenter.InitializeView();
        }

        _presenter.LoadView();

        //Other normal onload stuff here...
    }

    //Now for the interface stuff
    public Int32 ID
    {
        get{ return Int32.Parse(lblOrderId.Text); } 
        set{ lblOrderId.Text = value.ToString(); }
    }

    public String Name
    {
        get{ return lblOrderName.Text; } 
        set{ lblOrderName.Text = value; }
    }

    public List<Item> Items 
    {
        set
        {
            gvItems.DataSource = value;
            gvItems.DataBind();
        }
    }
}

And there you have it! You should be able to write unit tests against the OrderPresenter now using a stubbed out View. No HttpContext required, and you have cleaner seperation of concerns.

If you already have all your business logic seperated out then I appologize, but I can't think of any other reason to test a server control outside the ASP.Net runtime besides needing to verify actual business logic. If this is the case, then I would highly encourage you to refactor now before you realize the maintenance nightmare this will eventually cause via Leaky Abstractions.

Josh