views:

370

answers:

3

I'm currently writing some methods that do some basic operations on form controls eg Textbox, Groupbox, these operations are generic and can be used in any application.

I started to write some unit tests and was just wondering should I use the real form controls found in System.Windows.Forms or should I just mock up the sections that I'm trying to test. So for example:

Say I have this method which takes a control and if it is a textbox it will clear the text property like this:

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

Then I want to test this method so I do something like this:

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

Should I be adding a referance to System.Window.Forms to my unit test and use the real Textbox object? or am I doing it wrong?

NOTE: The above code is only an example, I didn't compile or run it.

+4  A: 

If you're trying to unit test the application logic by simulating interaction with the UI controls, you should do some abstraction using the MVC pattern. Then you can just have a stub view and call the controller methods from your unit tests.

If it's the actual controls you're trying to unit test, you've got me.

Cristi Diaconescu
I agree, there is no real use in testing the .NET Framework. Microsoft does that already to a pretty great extent :).
Tigraine
+2  A: 

What you are suggesting won't even compile if your code relies on System.Windows.Forms.Control. Your version of Control and Textbox are simply the wrong type.

If, instead, you separated your UI and Logic with interfaces, then you could do this... Something like this:

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

Then, in your test, all you need to do is create a mock, fake or stub ITextBox and pass it in.

When I do something like this, I create an interface at a slightly higher level... I create an interface that looks a lot like the entire UI and have the UI implement the interface. Then, I can twiddle the UI all I need, without ever really knowing that it is a Forms control.

By the way, if you want to go with the approach of creating actual controls, consider this blog post about it: http://www.houseofbilz.com/archive/2008/10/12/winforms-automation-extensions.aspx

Brian Genisio
+2  A: 

There are several patterns that are useful for separating UI presentation from UI logic including Model-View-Controller and the various incarnations of Model-View-Presenter (AKA Humble Dialog). Humble Dialog was concocted specifically to make unit testing easier. You should definitely have one of these UI patterns in your design arsenal.

But I have found that for simple forms, when the framework supports it, it's quite straightforward to test directly against the real UI controls. I have built quite robust UIs completely test-first in Java Swing and Windows.Forms. I couldn't manage it in SWT or ASP.NET and reverted to MVP.

For testing things like this...

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

...working directly against the UI controls works fine. But if you want to start testing mouse moves, keystrokes or drag and drop, you'd be better off choosing a more robust UI pattern like the one suggested by Brian.