Home
News
Documentation
License
Download
Contributors
Source Code
NUnit
NMock
SourceForge
|
|
API Documentation
Click here for MSDN style API docs
Building
- Unzip the file to any directory.
- 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
- Start the NUnitFormsRecorderApplication.exe
- It will prompt you to select a dll. Browse to and select the .dll that contains the form you want to test.
- 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.
- 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.)
- 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"
- 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
- Extend the ControlTester class like this:
public class ComboBoxTester : ControlTester
- 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){}
- 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;
}
}
- 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;
}
}
- 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
- Extend the ControlRecorder class like this:
public class ComboBoxRecorder : ControlRecorder
- Override the RecorderType Property like this. It should return the type of control this recorder records.
public override Type RecorderType
{
get
{
return typeof(ComboBox);
}
}
- Override the TesterType Property like this. It should return the type of the associated ControlTester.
public override Type TesterType
{
get
{
return typeof(ComboBoxTester);
}
}
- Implement a constructor like this:
public ComboBoxRecorder(Listener listener) : base(listener){}
- 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:
public void Click(object sender, EventArgs args)
{
listener.FireEvent(TesterType, sender, "Click");
}
public void TextChanged(object sender, System.EventArgs e)
{
listener.FireEvent(TesterType, sender, "Enter", ((ComboBox)sender).Text);
}
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);
}
- 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.
|