| « NAnt 0.85-RC1, TestDriven.Net 1.0 final | A read-only IDictionary wrapper for .Net 1/1.1 » |
NUnitForms and TestDriven.Net
Yesterday I started adding test to a windows form application. Until now I only tested non graphic libraries, but was concerned about how to lock the behavior of a graphic application. Graphic applications (both web and non-web) are usually very likely to regress from a functional point of view, and seem to generate a lot of support ("Didn't you fix that already ?"), maybe because an inspired gui tester has that kind of black magic skills to find new, undiscovered ways to use your application ("This *cannot* happen!! How did you do that?")
Anyway. I started small - a few tests, with a small application.
For regular (non graphic) tests, I used classic NUnit tests. And when I started testing forms, I checked out NUnitForms, which is an "NUnit extension for unit and acceptance testing of Windows Forms applications".
Setting up
For a practical point of view, when testing libraries I usually create a separate test project, and most of the time unit test the public parts of the tested assemblies which are located in other projects in the solution.
But this time, at least under VS.Net 2003 this won't work : I can't reference an "application project" assembly from another project (although it is allowed by the c# compiler itself, the IDE is not letting us do it).
So I decided to put the tests inside the application, in a separate Tests sub-namespace. This way I can cope with the IDE limitation, plus avoid the visibility issues.
There's plenty of other ways to do that of course (and debates around it as well), but that's not the purpose of this post.
To finish the setup, I just added nunit.framework.dll and NUnitForms.dll to the application assembly references.
Writing a test
Apart from usual NUnit test I wrote for the same application, I wanted to start testing a form. This form is called ErrorReportingForm, has a LinkLabel called _close which should manage to close the form, and an ErrorText property which value should be dumped into a TextBox called _errorMessage, along with other informations (including the list of assemblies in current appdomain).
Here's the test code first :
using System; using NUnit.Framework; using NUnit.Extensions.Forms; using DotNetGuru.Examples.Forms; namespace DotNetGuru.Examples.Forms.Tests { [TestFixture] public class ErrorReportingFormTest { bool hasClosed=false; private void form_Closed(object sender,EventArgs args) { hasClosed=true; } [Test] public void CloseForm() { ErrorReportingForm form = new ErrorReportingForm(); form.Closed+=new EventHandler(form_Closed); form.Show(); LinkLabelTester ctrl = new LinkLabelTester("_close",form); ctrl.Click(); Assert.IsTrue(hasClosed); } [Test] public void TextBoxShouldContainMessage() { ErrorReportingForm form = new ErrorReportingForm(); form.ErrorText="This is the error I want to display"; form.Show(); TextBoxTester ctrl = new TextBoxTester("_errorMessage",form); Assert.IsTrue(ctrl.Text.IndexOf("This is the error I want to display")!=-1); } } }
First thing is there's no breaking change with NUnit, only extensions. I have to import the NUnit.Extensions.Forms namespace in addition to NUnit.Framework. Then I declare my TestFixture and Test as usual.
I wanted to ensure the close button really close the windows. What's the need for that ? I just want to detect if no exception is thrown, for instance.
With NUnitForms I just instanciate the form. To be informed that the form has closed I hook up the Closed event. Then I call Show(), which causes NUnitForms to open the form in a separate, hidden desktop.
Then I use the NUnitForms tester objects to simulate actions on the control named "_close", then check that my callback has been called.
NUnitForms (now 1.3.1) provides support for a part of the Windows Forms (including "Buttons, CheckBoxes, ComboBoxes, Labels, ListBoxes, RadioButtons, TabControls, TextBoxes, TreeViews, Context Menus, Forms, MenuItems, Modal Forms, Modal MessageBoxes, and the Mouse", the list is growing), and still leave you with the opportunity to use a generic ControlTester class if the control you want to test is not yet supported (or not at all).
I should also mention that it comes bundled with a Recorder application with confused me a bit first (you have to select which form you want to test in the dropdown list), but which is handy once you have it working: it let you interact with the form and record what's happening (in term of real, typed events, not (x;y) click coordinates like other test recording tools). You just have to copy and paste the generated code into your test project to start testing.
Running and debugging tests with TestDriven.Net
For those who don't know it yet, TestDriven.Net is a VS.NET add-in to allow running and debugging unit tests in a very comfortable way. The latest release can be found here.
The good news is : it works perfect with NUnitForms so far!
Just like any other NUnit test, I can run a NUnitForms test, debug it step-by-step, put breakpoints etc. Isn't that sweet ?
The build process
Just as seamless, my CruiseControl.Net + NAnt setup accepted the NUnitForms tests and properly executed them.
Time to leave
It is actually simpler than what I expected to *start* testing graphical user interfaces, and now the tools under .Net are getting very well integrated to achieve that.
There are a lot more questions on how to test more complex things (just like for classical nunit tests when it comes to database testing, distributed testing, nmock etc), but at least the beginning is promising and I'll explore more.
Edit (25/11/2004) : Jose Almeida has blogged about another way to setup NUnitForms which I would use for a bigger application, ie. having three projects (one bootstrap .exe, one assembly with all the app code, and one assembly with all the tests).
27 comments
BUT still there is a lack of info about how to use this tool .
like:
How to built the apllication in the right order
is their more than one way to do it ??
and more...
is their any complete manual instruction that tell you exactly what to do ??
i dont want to miss something
the deeper the better !!!
by regards
eldad!!!
> How to built the apllication in the right order
What do you mean exactly ?
Are you talking about how to setup dependencies in a visualstudio.net project ? In this simple example there is no need to use that.
Please i need all the help you can give me, as soon as possible.
Thanx a lot,
regards,
That was a very detailed blog about NUnitForms.
I have a VB 6.0 GUI app that I am migrating to VB.NET. I would like to use NUnitForms for testing the forms as I migrate them one by one.I just got started with NUnitForms, but have several questions that I have in mind.
When you are testing your form, you say the form is displayed in the Hidden Desktop. I noticed that the form is displayed, but only the title of the form matches my original title. Meaning the form that we see duing the test is sort of like a skeleton of the original form. Is this the way it is or am I missing something?
Secondly I am a little confused about testing the results of actions of the controls on the form. You have an example in your blog, but I still have questions.
Lets say I have a form with a button called cmdOK. The purpose of this button is to close the form. Now I want to test my form for this functionality and so I create a test button. Does this button need to have the same name as my cmdOK button, i.e. the name of the cooresponding button on the form?
Also I am finding it hard to understand as to how the methods in the form are invoked using this test control.
Your help would be appreciated.
Thanks.
Do you know if it is possible to test controls that have been created dynamically on the form and not at design time ? I have not found a way to make this work...
I have also some problems with some third-party components that does not derive from System.Windows.Forms.Control but from System.ComponentModel.Component. (I think this is the problem, but I am not sure). Is it possible in that case to test them with NUnitForms?
By the way, is there somewhere detailed documentation about NUnitForms (the documentation on the website treats only of very standard cases...)? Or a group/forum about it?
Thanks by advance,
Verane.
But if u want - make it !
How do we navigate from menu to activate sub menus?
Is there support for Visual Studio 2003?
Is there support for Visual Studio 2005?
The WinForm application are not able to load due to issues
1. Drag Drop
2. STAThread.
Thanks