【问题标题】:Stubbing ASP.NET Page.Form for unit tests为单元测试存根 ASP.NET Page.Form
【发布时间】:2011-07-02 01:00:25
【问题描述】:

为了对 ASP.NET 控件进行单元测试,我需要一个存根页面。

我可以通过继承 System.Web.UI.Page 在我的单元测试中创建一个 ASP.NET Page 对象。 但是,我找不到设置 Page.Form 的方法。添加带有属性的表单 (runat,server) 不起作用。在我的子类中重载表单并没有提供所需的功能。

上下文: 我尝试对一些自制的 ASP.NET 控件进行单元测试。这些控件要求 Page 和 Page.Form 不能为空。

有什么建议吗?

【问题讨论】:

    标签: c# .net asp.net vb.net unit-testing


    【解决方案1】:

    尝试定义实现所需方法和属性的IPageIForm 接口,并创建实现这些接口的类并包装PageForm 类。这样您就可以测试这些控件中的逻辑,而无需在单元测试期间调用 ASP.NET 框架。

    更新:

    覆盖页面属性会很脆弱,不建议使用。相反,您应该尽量减少不可测试代码的数量,方法是在不依赖于任何 ASP.NET 特定(难以测试)部分的方法中提取逻辑。看看下面的例子:

    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;
            }
        }
    }
    

    通过从难以测试的方法中提取逻辑,您可以直接在测试中调用这些提取的方法。例如:

    [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);
    }
    

    如果您能够将被测代码提取到它自己的类中并从您的 WebControl 中调用它,那就更好了。然而,这并不总是可能的。

    我希望这是有道理的。

    【讨论】:

    • 我使用的控件继承自 System.Web.UI.WebControls.Label
    • 我们的类继承自 System.Web.UI.Control 并且该类实现了 Page 属性。您的建议将要求我覆盖 te Page 属性并添加 IPage 的 Page2 属性?
    • 我喜欢你的 pagewrapper 方法。仍然必须下定决心如何使 IPage 对象可用于我的方法。我想我会使用构造函数注入到受保护或私有属性中。
    【解决方案2】:

    您到底想测试什么?如果您正在测试的内容不完全依赖于页面本身,那么您可能可以避免需要一个页面实例,从而为自己节省很多心痛。看看下面的链接:

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

    但是,如果您要测试的内容确实取决于页面类,请使用您自己的类来包装它,该类提供对数据的访问方法。然后将该类转换为接口,用作方法或构造函数的参数。

    例子:

    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);
    }
    

    【讨论】:

      【解决方案3】:

      几年前我在使用 ASP.NET 时遇到了同样的问题,我们实现了 Fowler's «Passive View» pattern,并设法对所有逻辑进行了单元测试(并将相当愚蠢的视图的测试留给了手动测试)。

      【讨论】:

      • 这正是我所做的。我们使用被动视图,但控制器从视图组件中获取名称/值对,并将其存储在模型中。当然,过去的时间/重点不允许进行单元测试。我现在用单元测试记录了控件属性的行为,并添加了一个测试,通过将生成的字符串加载到 linq XElement 中来查看呈现的 html 是否格式正确,并查看是否出现异常。在该部分中,我们对 Page.form 有一个实际上不需要的硬依赖。我将使用类似 Steven 的解决方案来解决它。
      猜你喜欢
      • 2012-04-12
      • 1970-01-01
      • 1970-01-01
      • 2010-10-10
      • 2015-04-17
      • 2011-08-03
      • 1970-01-01
      • 1970-01-01
      • 2020-05-25
      相关资源
      最近更新 更多