这听起来很像您根本不关心控件的实际呈现,而是关心控件中包含的逻辑。为此,我建议您除了无法测试 HttpContext 之外的控件之外还有另一个问题。
如果逻辑只与控件有关,那么您应该信任框架来完成它的工作,并将控件放在页面上以查看它是否正常工作。如果您尝试测试的逻辑是业务逻辑,那么您需要重构。
将业务逻辑提取到某个地方的单独项目/Dll 中,并考虑使用您的服务器控件实现MVP pattern。您也不必使用像 WCSF 这样的大型框架。从概念上讲,您可以毫不费力地实现这一点。
创建一个代表视图上的值的接口:
public interface IOrderView
{
Int32 ID{get; set;}
String Name{get; set;}
List<Item> Items {set;}
}
一旦定义好,您就需要一个演示者来练习这个视图:
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
}
}
现在你的服务器控件可以实现这个接口,并用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();
}
}
}
你有它!您现在应该能够使用存根视图针对 OrderPresenter 编写单元测试。不需要 HttpContext,您可以更清晰地分离关注点。
如果您已经将所有业务逻辑分离出来,那么我很抱歉,但除了需要验证实际业务逻辑之外,我想不出任何其他理由在 ASP.Net 运行时之外测试服务器控件。如果 是这种情况,那么我强烈建议您在意识到这最终将通过Leaky Abstractions 导致的维护噩梦之前立即进行重构。