An NUnitForms testing strategy

by Paul Kohler 13. March 2008 00:27

These are basically some notes about to a GUI testing strategy I have adopted over the last year or so with NUnitForms. I am not going into what NUnitForms are etc here (because there an old NUnitForms post here) so I am assuming that you have at least some (or willing to get some) experience with the open source library prior to reading this post.

For a basic test fixture, typically you will inherit from the NUnitFormTest class overriding the Setup method:

[TestFixture]
public class FormXyzTests : NUnitFormTest{ 
 public override void Setup() 
 {
  new VesselDetailForm().Show();
  Application.DoEvents();
 }
 [Test] 
 public void CheckBla()
 {
  ButtonTester goButton = new ButtonTester("btnGo");
  LabelTester statusLabel = new LabelTester("btnGo");
  goButton.Click();
  Assert.That(statusLabel.Text, Is.EqualTo("Done."));
 }
}

When you test a button click you create a ButtonTester and initiate the Click method perform asserts and go home happy that your GUI is in a working state.

In the interests of refactoring GUI test that can quickly get bloated if you are not careful, I have ended up creating “form testers” that are in turn inherited by the test fixture. The form tester sets up a particular “scenario” and provides control testers and other helper methods through properties, for example:

public class FormXyzTester : NUnitFormTest
{
 public override void Setup()
 {
  VesselDetailForm frm = new VesselDetailForm();
  frm.Show();
  Application.DoEvents();
 }
 public ButtonTester GoButton
 {
  get { return new ButtonTester("btnGo"); } 
 }
 public LabelTester StatusLabel
 {
  get { return new LabelTester("lblStatus"); }
 }
}
 

Now the fixture inherits from the form tester and the tests are more readable.

[TestFixture]
public class FormXyzTests2 : FormXyzTester
{
 [Test]
 public void CheckBla()
 {
  GoButton.Click();
  Assert.That(StatusLabel.Text, Is.EqualTo("Done."));
 }
}

As other form specific related test helpers are required I add them to this base class. If needed, I also split this further with another base form tester class with common functionality. Other things I have included in these form testers are the message box responders, logging, even reporting and facilities to take screen shots of the application as its testing. These all help make for some very robust GUI testing classes.

PK Smile

 

Tags:

NUnitForms

Tip - Use failing Unit Tests to mark your TODO Items

by Paul Kohler 31. October 2007 23:40
It's common practice for developers to make small "TODO" notes in code as they work for themselves or others to clarify at some time...

// TODO: confirm this business requirement...
// TODO: make this better!
// TODO: bread, butter, eggs and milk...

Issues can arise when the TODO's are not taken care of for whatever reason or get lost in the mayhem of meeting deadlines. A worst case scenario could arise when there is a production defect for an obscure situation and the maintenance programmer finds something like this:

// TODO: Not sure if there are any more response codes for this one, check before release.

Opps! Now that's expensive.
Now I am not saying this is good or bad (!) practice - but what I have started to do within my team is create either a failing or ignored unit test (depending on the importance) marking what would normally be an innocent "TODO" item. The unit test stays in the build as either a fail or ignore and does not drop off the radar.

[Test]
public void Need_to_confirm_foo()
{
  Assert.Fail();
}

Or...

[Test]
[Ignore("Confirmation required from the business")]
public void A_foo_only_has_a_bla()
{
}

It's much harder to miss a bunch of ignored or failing unit tests before that production release than some well hidden TODO comments!

 

An NUnitForms Note for the Form Shown Event

by Paul Kohler 13. June 2007 23:30

Just a quick note that could drive you completely mad if you were not aware...

If you are using NUnitForms for testing your GUI and have code in the forms "Shown" event, it will not run unless you follow the Form.Show call with Application.DoEvents(), see sample code below

This example is just a Label (label1) dumped on a Form with the Load and Shown events updating the label with the respective event text:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace NUnitFormsDemo1
{
    public partial class ShownTestForm : Form
    {
        public ShownTestForm()
        {
            InitializeComponent();
        }

        private void ShownTestForm_Load(object sender, EventArgs e)
        {
            label1.Text = "Load";
        }

        private void ShownTestForm_Shown(object sender, EventArgs e)
        {
            label1.Text = "Shown";
        }
    }
}

Here is some sample NUnitForms test code, the first test asserts that after the Form.Show call the label text is "Load" and the second test shows that the label text is "Shown".

using System;
using System.Windows.Forms;
using NUnit.Framework;
using NUnit.Extensions.Forms;

namespace NUnitFormsDemo1.UnitTests
{
    [TestFixture]
    public class TestFormShownIssue : NUnitFormTest
    {
        [Test]
        public void TestFormShow()
        {
            ShownTestForm frm = new ShownTestForm();
            LabelTester label1Tester = new LabelTester("label1");
            frm.Show();
            Assert.AreEqual("Load", label1Tester.Text);
        }

        [Test]
        public void TestFormShowWithDoEvents()
        {
            ShownTestForm frm = new ShownTestForm();
            LabelTester label1Tester = new LabelTester("label1");
            frm.Show();
            Application.DoEvents(); // allows the 'Shown' event to fire
            Assert.AreEqual("Shown", label1Tester.Text);
        }
    }
}

 

I will take an educated guess that this is due to the GUI message pump etc.

In general if I come across this any of this type of unexpected behavior with NUnitForms I will try a DoEvents before tearing my hair out.

Working with unsupported controls in NUnitForms

by Paul Kohler 21. March 2007 02:32

Another sequel to the entry on "Getting Started with NUnitForms"

  http://www.pksoftware.net/devblog/post/2007/02/Getting-Started-With-NUnitForms.aspx

This post is focused on compiling the latest NUnitForms code from sourceforge.

I have seen/heard/had a few questions about testing windows forms controls that are not currently supported by NUnitForms (specifically ".Net 2.0 NUnitForms alpha 5 release" - http://sourceforge.net/project/showfiles.php?group_id=95656).

There are 2 answers...

  1. Cut your own (see the "How to add Control Testers" section at http://nunitforms.sourceforge.net/docs.html), or
  2. Get the latest source out of the subversion repository and use the generic tester class...
The subversion connection details are here: http://sourceforge.net/svn/?group_id=95656

You will need TortoiseSVN (http://tortoisesvn.net/) or similar to get the files.

 



Note that all related files for the build are also downloaded (nant, nunit, ncover and ndoc etc) so there won’t be any messing around trying to find the correct library dependencies (ahhh!) Of course, because of this the download is about 8.5mb...

Now... from here on in things could get a little messy. You could have problems with key containters, there may be a duplicate "ButtonTestser.cs" file... The list was getting a little long - the short answer to the "problems" were to compile the NUnitForms project after modifying the signing method of the 2 projects "NUnitForms" and "NUnitForms.ScreenCapture". You will also need to delete the AssemblyKeyName code references in the relevent AssemblyInfo.cs files.



Keep in mind that when you get the latest out of a code repository this sort of thing is not unexpected or "bad". Its a work in progress...

Now the latest build of the NUnitForms DLL will give you access to the generic control tester class. When you need to test a control that does not have its own tester class (e.g. ButtonTester) you can use the generic declaration and create your own tester class, e.g. for a picture box:


public class PictureBoxTester : ControlTester<PictureBox, PictureBoxTester>
{
  // Now implement each overloaded constructor calling the base class
  public PictureBoxTester() {}
  public PictureBoxTester(string name, Form form) : base(name, form) {}
  public PictureBoxTester(string name, string formName) : base(name, formName) {}
  public PictureBoxTester(string name) : base(name) {}
  public PictureBoxTester(ControlTester tester, int index) : base(tester, index) {}
}



Now in the tests you can create tester objects and access all the properties and perform clicks etc:

[Test]
public void ExamplePropertyCheckAndDoubleClickTest()
{
  PictureBoxTester picTester = new PictureBoxTester("pictureBox1");
  Assert.AreEqual(@"C:\dir\somePic.bmp", picTester.Properties.ImageLocation);
  picTester.DoubleClick();
}


Easy as pie right?! Well sort of. But much easier than writing your own windows forms GUI testing framework!!

PK  ;-)

Getting Started with NUnitForms - GUI Testing with Message Boxes

by Paul Kohler 13. February 2007 02:19

A sequel to the entry on "Getting Started with NUnitForms"

  http://www.pksoftware.net/devblog/post/2007/02/Getting-Started-With-NUnitForms.aspx

This post is focused on handling the testing of message boxes in an application.

Another common test requirement that you will probably come across in the GUI world is the use of message boxes. To handle a message box with NUnitForms (i.e. simulate a user click or similar), use a "message box handler" method. Firstly set up the test to "expect" a message box and then supply the name of the method to handle the reaction:

[Test]
public void MessageBoxTest()
{
   base.ExpectModal("Info", "MessageBoxTestHandler");
  ButtonTester runButton = new ButtonTester("RunButton");
  runButton.Click();
}

This tells the test sub-system that a message box is expected and the title should be "Info". Also supplied is the name of a handling method - in this case "MessageBoxTestHandler". This method should create a "MessageBoxTester" and (most likely) click the OK button:

public void MessageBoxTestHandler()
{
  MessageBoxTester messageBox = new MessageBoxTester("No Item Selected");
  messageBox.ClickOk();
}

Other useful methods of the MessageBoxTester class are "ClickCancel" and "SendCommand(cmd)" where "cmd" is an enum value of type MessageBoxTester.Command:
  • OK
  • Cancel
  • Abort
  • Retry
  • Ignore
  • Yes
  • No
  • Close
  • Help
For example:

public void MessageBoxTestHandler()
{
  MessageBoxTester messageBox = new MessageBoxTester("Cancel, are you sure?");
  messageBox.SendCommand(Command.Yes);
}

A practical application of this could be tests where for example if search criteria is not supplied a "no criteria" message box is displayed. Boundary checks in methods are common places for bugs to occur so make sure you perform the same boundary check on the GUI layer!

About the author

Paul Kohler, .net developer living and working in Brisbane, Australia...

Email me via the contact page or browse to the main PK Software site.