Caves Travel Diving Graphics Mizar Texts Cuisine Lemkov Contact Map RSS Polski
Trybiks' Dive Texts Testing Automated Testing of Window Forms YAC Software












Rhino Mocks



UI Testing




Automated Testing of Window Forms
Someday I really got tired of testing the various forms in my Delphi applications. Especially those shortcuts (duplicate shortcut keys on the same form or in a menu) and tab orders... So I thought that it might be a bit better to let the computer do it. :-)

So, what should/could be automatically tested in a form?

I came up with the following list:
  • Shortcuts in modal forms/windows
    Checks that a shortcut letter in a modal form is not repeated in two different captions.
  • Shortcuts in menus (main and popup)
    Checks that a shortcut letter is not repeated in the same menu; note that submenus should be treated separately so that different submenus may have repeating shortcut letters.
  • Shortcuts between a window and its main menu
    Checks that a shortcut letter is not repeated between captions of the window and the window's main menu captions; this is mostly useful in SDI applications.
  • Accelerators (as in F1, Ctrl+S, etc.)
    Checks that a given accelerator combination is assigned to at most a single item (action, menu, button).
  • Tab orders
    Checks that controls in a window go from left to right and top to bottom; obviously you may want to enforce other rules here, but this is the order that's most natural to me.
  • Shortcuts on labels
    Checks that a label has either:
    • a single shortcut defined (using &), FocusControl assigned, and ShowAccelChar set to TRUE,
    • or FocusControl set to NIL and ShowAccelChar set to FALSE.
  • Shortcuts on buttons
    In my applications I enforce the following rule: all buttons must have shortcuts assigned, except the Cancel (mrCancel) button. This includes the default button (usually with the caption "OK" where 'K' is the shortcut), because when you switch focus in a dialog window to any button, the "enter" key doesn't "press" the default button, but the selected/current button. So, in effect, you don't have a shortcut to the default button then.
  • Miscellaneous, such as:
    • A modal window has a default button.
    • A modal window has an mrCancel button.
    • A button has either an action assigned or an OnClick event assigned (or they point to the same handler).
    • Group boxes don't have shortcuts, but all check boxes and radio buttons do.
    • Dangling event handlers (for instance, a FormShow procedure that is not assigned to the OnShow event).
  • ... and I'm sure there are many more situations that can be checked.
One more thing to note here is that if you have tabsheets on your forms, then you should check tabsheets against the form and not against other tabsheets. And this starts to be a bit more complicated when you have nested tabsheets... :-)

Finally, note that it's usually enough to instantiate and show your forms during unit tests to find most of the errors above, so you don't even have to check for those errors during program execution. However, some errors may not show up during such simple unit tests. For instance, when you're creating controls at runtime, or when tabsheets are present on the form, or when you're using menu merging in MDI applications... Then, either you must enhance your unit tests or... just run the program.

If you're going to be testing the form during program execution, the following notes may come in handy (this is Delphi, but should be easy enough in other languages/systems):
  • Add a property to a form base class that is initialized to FALSE and set to TRUE if a problem was already found in that form.
  • Add a procedure that runs the checks above only when the property is FALSE and sets the property to TRUE when a problem is found.
  • Call the procedure in the OnIdle event handler.
The last point will run these tests whenever the program enters the idle state. This is helpful when the interface changes during program execution.

The first two points are needed to stop error reporting when an error was found - since errors are being reported in OnIdle, the same error would be reported over and over.

I think this is really worth implementing - it saves hours and hours of testing time since any errors come up right away during implementation (either in unit tests or on program execution). And obviously you may wish to implement only a subset of the rules listed above, or many other rules that I haven't even thought of.


No comments yet...


Add a comment (fields with an asterisk are required)
Name / nick *
Mail (will remain hidden) *
Your website
Comment (no tags) *
Enter the text displayed below *






Related pages

AssertWasCalled and Methods Called Multiple Times

AssertWas[Not]Called and Object Properties

Rhino Mocks's AssertWasNotCalled

Visual Studio - moving coded UI tests to a new / different project results in null reference exceptions

PrivateObject and Out/ByRef parameters

PrivateObject, WithEvents, and generics

Delphi interfaces... again

Accessing private members of base classes

PrivateObject and WithEvents

Accessing private and protected members - PrivateObject and PrivateType

VS - Test Run Error - "COM object that has been separated from its underlying RCW cannot be used"

Get the TreeViewItem for an Item in a WPF TreeView

Output in MSTest Tests (VS 2010)

Automated WPF tests and "Invalid URI: Invalid port specified."

Checking Property Change Notifications

Checking "Dangling" Event Handlers in Delphi Forms

Rhino Mocks's AssertWasCalled in VB.NET

First steps with Rhino Mocks (in VB.NET)

VS Pending Tests

Drag-n-drop files onto the application window

Intraweb and MaxConnections

A Case for FreeAndNIL

Intraweb as an Apache DSO module

"Device not supported" in Intraweb

Automated GUI Testing

Rounding and precision on the 8087 FPU

SessionTimeout in Intraweb

Using TChart with Intraweb

Unknown driver: MySQL

Automated GUI Testing in VMs

TIdMessage's CharSet

Software Guarantees

TChart - Missing Labels in Axes

Memory Leaks and Connection Explosions in DBExpress

Controlling Conditional Defines and Compilation Switches

Detecting Memory Leaks with DUnit

last_insert_id() and DBExpress

Registering Extensions

DBExpress and Thread Safety

Forms as Frames

Checking Dangling Pointers vs. the New Memory Manager

Accessing Protected Members

Objects, interfaces, and memory management in Delphi