【问题标题】:Unit testing method that uses UI controls使用 UI 控件的单元测试方法
【发布时间】:2008-11-19 13:11:28
【问题描述】:

我目前正在编写一些对表单控件执行一些基本操作的方法,例如 Textbox、Groupbox,这些操作是通用的,可以在任何应用程序中使用。

我开始编写一些单元测试,只是想知道我应该使用 System.Windows.Forms 中的真实表单控件,还是应该只是模拟我正在尝试测试的部分。比如:

假设我有这个方法,它需要一个控件,如果它是一个文本框,它将像这样清除文本属性:

        public static void clearall(this Control control)
        {
            if (control.GetType() == typeof(TextBox))
            {
                ((TextBox)control).Clear();
            }
        }

然后我想测试这个方法,所以我做了这样的事情:

        [TestMethod]
        public void TestClear() 
        {
            List<Control> listofcontrols = new List<Control>();
            TextBox textbox1 = new TextBox() {Text = "Hello World" };
            TextBox textbox2 = new TextBox() { Text = "Hello World" };
            TextBox textbox3 = new TextBox() { Text = "Hello World" };
            TextBox textbox4 = new TextBox() { Text = "Hello World" };

            listofcontrols.Add(textbox1);
            listofcontrols.Add(textbox2);
            listofcontrols.Add(textbox3);
            listofcontrols.Add(textbox4);

            foreach (Control control in listofcontrols)
            {
                control.clearall();
                Assert.AreEqual("", control.Text);
            }
        }

我是否应该在我的单元测试中添加对 System.Window.Forms 的引用并使用真正的 Textbox 对象?还是我做错了?

注意:上面的代码只是一个例子,我没有编译或运行它。

【问题讨论】:

    标签: c# unit-testing mocking


    【解决方案1】:

    如果您尝试通过模拟与 UI 控件的交互来对应用程序逻辑进行单元测试,您应该使用 MVC pattern 进行一些抽象。然后你可以有一个存根视图并从你的单元测试中调用控制器方法。

    如果它是您尝试进行单元测试的实际控件,那么您就知道了。

    【讨论】:

    • 我同意,测试 .NET Framework 并没有真正的用处。微软已经在很大程度上做到了这一点:)。
    【解决方案2】:

    有几种模式可用于将 UI 表示与 UI 逻辑分开,包括模型-视图-控制器和模型-视图-演示者的各种化身(AKA Humble Dialog)。 Humble Dialog 是专门为简化单元测试而设计的。您绝对应该在您的设计库中拥有这些 UI 模式之一。

    但是我发现对于简单的表单,当框架支持它时,直接针对真实的 UI 控件进行测试是非常简单的。我已经在 J​​ava Swing 和 Windows.Forms 中构建了非常健壮的 UI,完全以测试为先。我无法在 SWT 或 ASP.NET 中管理它并恢复为 MVP。

    为了测试这样的东西......

    [Test] public void ShouldCopyFromAvailableToSelectedWhenAddButtonIsCLicked(){
      myForm.AvailableList.Items.Add("red");
      myForm.AvailableList.Items.Add("yellow");
      myForm.AvailableList.Items.Add("blue");
    
      myForm.AvailableList.SelectedIndex = 1;
      myForm.AddButton.Click();
    
      Assert.That(myForm.AvaiableList.Items.Count, Is.EqualTo(2));
      Assert.That(myForm.SelectedList.Items[0], Is.EqualTo("yellow"));
    }
    

    ...直接针对 UI 控件工作可以正常工作。但是,如果您想开始测试鼠标移动、击键或拖放操作,最好选择像 Brian 建议的那样更健壮的 UI 模式。

    【讨论】:

      【解决方案3】:

      如果您的代码依赖于 System.Windows.Forms.Control,您的建议甚至不会编译。您的 Control 和 Textbox 版本完全是错误的类型。

      如果相反,您将 UI 和 Logic 与接口分开,那么您可以这样做......像这样:

      public interface ITextBox
      {
          public string Text {get; set;}
      }
      
      public class TextBoxAdapter : ITextBox
      {
          private readonly System.Windows.Forms.TextBox _textBox;
          public TextBoxAdapter(System.Windows.Forms.TextBox textBox)
          {
              _textBox = textBox;
          }
      
          public string Text
          {
              get { return _textBox.Text; }
              set { _textBox.Text = value; }
          }
      }
      
      public class YourClass
      {
          private ITextBox _textBox;
          public YourClass(ITextBox textBox)
          {
              _textBox = textBox;
          }
      
          public void DoSomething()
          {
              _textBox.Text = "twiddleMe";
          }
      }
      

      然后,在您的测试中,您需要做的就是创建一个 mock、fake 或 stub ITextBox 并将其传入。

      当我做这样的事情时,我创建了一个稍微更高级别的界面......我创建了一个看起来很像整个 UI 的界面,并让 UI 实现了该界面。然后,我可以随意摆弄 UI,而无需真正知道它是一个 Forms 控件。

      顺便说一句,如果你想采用创建实际控件的方法,请考虑这篇博文:http://www.houseofbilz.com/archive/2008/10/12/winforms-automation-extensions.aspx

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-11-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多