Home
News
Documentation
License
Download
Contributors

Source Code

NUnit
NMock
SourceForge

SourceForge.net Logo

API Documentation

Click here for MSDN style API docs

Building

  1. Unzip the file to any directory.
  2. From a .NET command prompt, run test.bat to build the application.

Writing Unit Tests

Inside of an NUnit test, instantiate the Form to be tested and call its Show() method.

Form form = new Form();
form.Show();

For each control that you will use in the test, create an instance of the appropriate ControlTester by passing the name of the control.

  ButtonTester button = new ButtonTester("buttonName");

Each ControlTester provides some convenience methods for accessing common properties on the control and interacting with it in common ways. For example, there is a Click method on ButtonTester, and an Enter(string Text) method on TextBoxTester.

If you have more than one form open, you can specify the form that contains your control according to the form's name.

ButtonTester button = new ButtonTester("buttonName", "formName");

If you omit the "formName" parameter, NUnitForms will search all open forms for the control. It is only necessary to specify the form name with the control name alone does not uniquely identify the control. (If you have multiple instances of the same form class with identically named controls, the form name properties need to be distinct.)

The base ControlTester class can also be used to test arbitrary controls (without the convenience methods of course.) You can access properties on the control using the indexer property as shown here.

ControlTester textBox = new ControlTester("nameOfSomeTextBox"); Assertion.AssertEquals("defaultText", textBox["Text"];
textBox["text"] = "newText";

You can also attempt to cause the control to fire an event using the FireEvent method.

ControlTester button = new ControlTester("nameOfSomeButton"); button.FireEvent("Click");

(Notice that this is identical to calling the convenience method button.Click(); but there may not be convenience methods for every control you want to use. Of course the preferred approach is to add new convenience methods or new ControlTesters and submit them back as enhancements to NUnitForms :) )

Control naming

NUnitForms finds the controls you want to test by looking at their Name property. If you have multiple controls on a form with the same Name property, then you need to qualify the name as shown here.

Form
  PanelA
    UserControl1
      Button           (PanelA.UserControl1.Button)   
    UserControl2
      Button           (UserControl2.Button)
  PanelB
    UserControl1
      Button           (PanelB.UserControl1.Button)

The thing to notice is that you only have to qualify it enough to make it have a unique name. If NUnitForms can not find your control, it will throw a NoSuchControlException. If your name does not uniquely qualify the control (and needs to be better qualified) an AmbiguousNameException will be thrown.

Because controls can be dynamically added and removed on a form, these exceptions are not thrown until you actually attempt to use a control. The appropriately qualified name for a control can change over time. (The recorder application should handle this appropriately, using the shortest possible name for a control at all times. It might help to use the recorder application to determine the best form names... )

How to use the Recorder Application

  1. Start the NUnitFormsRecorderApplication.exe
  2. It will prompt you to select a dll. Browse to and select the .dll that contains the form you want to test.
  3. When the application window opens there is a drop down box containing a list of all the Form classes in the loaded .dll. Selecting one from the drop down causes the recorder to display your Form and start an empty unit test.
  4. As you work with the form, a test will be recorded that duplicates your actions. (At least it will record actions supported by NUnitForms and the recorder application.)
  5. By right-clicking on a control, you can insert an Assertion about any property on that control. The behavior of the recorder application can be extended by writing your own recorder classes. You can look at the source for the provided recorder classes as an example, or to the later section of documentation entitled "How to add Control Recorders"
  6. Once your test is written, copy and paste it into your unit test class. Of course it can be hand modified from that point.

An interesting feature is the the recorder application uses any recorder classes that are currently loaded along with your test form. If you "load" an assembly that has a custom recorder before selecting your tested form from the drop-down box, NUnitForms should use your custom recorder. This means that the recorder application can use your custom recorders without building them into the NUnitForms assemblies. (The same is true for custom Control Testers.)

Let me know if you would be interested in an NFit fixture for NUnitForms or if you would like to see the recorder extended to write NFit tests.

How to add Control Testers

ControlTesters should

  1. Extend the ControlTester class like this:

    public class ComboBoxTester : ControlTester

  2. Implement three constructors like this:

    public ComboBoxTester(string name, Form form) : base(name, form){}

    public ComboBoxTester(string name, string formName) :
                                             base(name, formName){}

    public ComboBoxTester(string name) : base(name){}

  3. For recorder support, implement a read-only property named "Properties" that returns an object with all the properties that you want displayed in the right-click Assertion recording feature of the recorder. The easiest way to do this is to expose all of the Properties of the underlying control by simply returning "Control" cast to the appropriate type. ("Control is a reference to the underlying control inherited from the base class.)

    public ComboBox Properties {
      get
    {
        return
    (ComboBox) Control;
      }
    }

  4. Implement as directly accessible properties and methods any commonly used properties and interactions with the control you are supporting.

    public void Select(int i) {
       Properties.SelectedIndex = i;
    }

    public string Text {
      get
    {
        return
    Properties.Text;
      }
    }

  5. Any ControlTesters distributed with NUnitForms should have unit tests for all of their functionality. The NUnitFormsTestApplications foler has several small and simple forms with representative controls specifically for the purposes of unit testing. In each release, I hope to have associated Recorders for each tester as well.

How to add Control Recorders

Control Recorders should

  1. Extend the ControlRecorder class like this:

    public class ComboBoxRecorder : ControlRecorder

  2. Override the RecorderType Property like this. It should return the type of control this recorder records.

    public override Type RecorderType {
      get {
        return
    typeof(ComboBox);
      }
    }

  3. Override the TesterType Property like this. It should return the type of the associated ControlTester.

    public override Type TesterType {
      get
    {
        return
    typeof(ComboBoxTester);
      }
    }

  4. Implement a constructor like this:

    public ComboBoxRecorder(Listener listener) : base(listener){}

  5. For each event that you want to record, create a method with a signature that matches the delegate type of the event you are recording. The name of the method should match the name of the event. The implementation of the method should call listener.FireEvent(). There are overloaded versions of listener.FireEvent() depending on what you are recording. Note the mapping here between what gets recorded as an event, and the associated convenience method in the ControlTester. Here are some examples:

    //records button.Click()
    public void
    Click(object sender, EventArgs args) {   listener.FireEvent(TesterType, sender, "Click");
    }

    //records: comboBox.Enter("text");
    public void
    TextChanged(object sender, System.EventArgs e) {   listener.FireEvent(TesterType, sender, "Enter",                             ((ComboBox)sender).Text);
    }

    //records: comboBox.Select(3); //text of item 3
    public void
    SelectedIndexChanged(object sender,System.EventArgs e){
      EventAction action = new EventAction("Select",                              ((ComboBox)sender).SelectedIndex);
      action.Comment = ((ComboBox)sender).Text;
      listener.FireEvent(TesterType, sender, action);
    }

  6. In some (hopefully rare) situations, you may have to override the EventKey method in the base Recorder class. I think I have handled the common cases of this in the framework in the base recorder class and will extend it as necessary.
Copyright 2003-2007 Luke T. Maxon. All Rights Reserved.