This post is the second in a series of posts, building a GUI test automation framework. In the previous post, I outlined that maintainability was one of our key design goals. There are two key techniques I use to develop maintainable tests.
1. Reducing the number of lines of code in a test to the absolute minimum.
2. Mapping the application’s GUI so when a control changes, you only need to change it’s definition in one place.
For this post I will base my example on the new Login control that ships with ASP.net 2.0.
Record and playback is evil
Recorded tests shouldn’t be used in any serious test automation approach. To show why, I will record entering a username, password and pressing the login button in an unnamed commercial tool.
' Begin Record on Monday, 21 May 2006 at 6:45:39
' PM by BruceM
' Attach to Untitled Page - Microsoft
' Internet Explorer Window
Window("Untitled Page - Microsoft Internet Explorer Window").Attach
' Attach to Caption='Untitled Page'
HTMLBrowser("Caption='Untitled Page'").Attach
HTMLEditBox("Name=Login1$UserName").Click 47, 11
HTMLEditBox("Name=Login1$UserName").SetText "username"
HTMLEditBox("Name=Login1$Password").SetText "password"
HTMLButton("Name=Login1$LoginButton").Click
' End Record on Monday, 21 May 2006 at 6:45:51 PM
' by BruceM
First things first, the code is just plain ugly. Indenting and spacing is all over the place, the comments are bad and it follows no known standard that I know of.
Now let’s say that we have this code at the start of every test, and we have 400 tests in our test suite. Our lead UI developer has decided to replace the login control with their own and he renames the login controls as follows:
"UserName" now becomes "txtUsername"
"Password" becomes "txtPassword"
"LoginButton" now becomes "btnLogin"
To change the control names in all our tests, we would need to change 1600 lines of code, and that is painful, not to mention a complete waste of time that could be spent elsewhere.
Enter the GUI mapping file
To avoid this situation, the fix is technically quite simple. If we define variables for all the controls in a single file, which all the tests refer to, we only need to update the mapping file in a single location instead of each and every test.
Mercury’s WinRunner uses this approach for it’s GUI map files, which contain all the definitions in a single file.
If aren’t using WinRunner, (I’m not), and your tool does not have a GUI map, you can simply extend your tool and “roll your own”. I have used various solutions to build GUI maps from XML files and the MSXML DOM, to a class that is full of public constants similar to the following.
Public Const LOGIN_PAGE as string = "Caption='Untitled Page'"
Public Const LOGIN_USERNAME_TEXTBOX as string = "Name=Login1$txtUserName"
Public Const LOGIN_PASSWORD_TEXTBOX as string = "Name=Login1$txtPasword"
Public Const LOGIN_BUTTON as string = "Name=Login1$LoginButton"
This method is nice that with a good tool, you should now have code completion happening in your editor. You also don’t have a runtime performance issue looking up controls in an XML file which you get with the DOM method.
Our updated code is now as follows:
' Begin Record on Monday, 21 May 2006 at 6:45:39
' PM by BruceM
' Attach to Untitled Page - Microsoft
' Internet Explorer Window
Window("Untitled Page - Microsoft Internet Explorer Window").Attach
' Attach to Caption='Untitled Page'
HTMLBrowser(LOGIN_PAGE).Attach
HTMLEditBox(LOGIN_USERNAME_TEXTBOX).Click 47, 11
HTMLEditBox(LOGIN_USERNAME_TEXTBOX).SetText "username"
HTMLEditBox(LOGIN_PASSWORD_TEXTBOX).SetText "password"
HTMLButton(LOGIN_BUTTON).Click
' End Record on Monday, 21 May 2006 at 6:45:51 PM
' by BruceM
Common GUI map gotcha’s
Moving all your controls to a GUI map solves one problem but creates another. With all the controls now being defined by your test developers, you can have different developers define the same control using different standards. e.g.:
Public Const LOGIN_PASSWORD_TEXTBOX as string = "Name=Login1$txtPasword"
Public Const TEXTBOX_PASSWORD as string = "Name=Login1$txtPasword"
I recommend that you should develop a standard, and stick to it. The goal is that if anyone adds a new control, it will have the same variable name regardless of who defined it. A standard may be PAGENAME_CONTROLNAME_CONTROL_TYPE, or tlaPagenameControlName. (Where tla is the three letter acronym for the control type, e.g. txt for a textbox.)
If you can just use the same standard the developers are using for the application itself.
At this point you might be asking, if the test code produced is completely un-maintainable, why do the tools provide that feature. The answer is that tool vendors are in the business of selling tools, not selling maintainable automated tests. Providing record and playback in an automated test tool allows testers who can’t code to quickly produce an automated test, by simply ignoring the maintainable test goal. Personally I only use record and playback to know what command I should be using to interact with a particular control, before rewriting that command myself.
In my next post in this series, I will cover using functions to reduce the number of lines of code in each test.

May 30th, 2006 at 3:36 pm
I assume that you are using the code as a sample rather than saying that the product that created this code does not support a “GUI map”. This looks suspiciously like code that was generated from TestPartner (exactly); if this is the case it should be noted that this product has a “GUI map” but it is called the “Object Map”. GUI map is a WinRunner term which is not an industry standard term. The upshot of this is that you can replace the “public const” entries with an object that can be used by any script; the other advantage is that the entry can use more than just the Name property.
You point about the comments, these can be suppressed in the setting, indenting is provided to show relationships between the window that is the parent vs. the controls that are being automated within the window.
Thoughts?
//*Eggbox
May 31st, 2006 at 3:21 am
Eggbox,
With these articles I am trying to be “tool neutral”, hence why I didn’t explicitly name the tool that I am currently using, yes it is Testpartner.
You are absolutely correct that GUI map is WinRunner specific, term I will try an use object map in the future.
We have consciously not using the object mapping functionality of Testpartner, and that is a design choice on our part. We prefer to have a small number of control files with hundreds of constants defined in them, instead of having hundreds of individual object maps. We also don’t use scripts, events, string maps and we only have a few checks.
The key point I was trying to make is that if your particular tool does not come with a feature you need out of the box, or you don’t like how it is implemented in a particular tool, you can implement your own if you need to.
February 8th, 2007 at 1:10 am
Hi Bruce,
Just wondering if you were interested in continuing this series. The construction of a GUI framework is looming on the horizon for me, and I’d be keen to read your experiences.
I have been reading your blog with interest for the last 6 months and you’ve totally got me switched on to WatiN – thanks for that.
Regards
Piers
February 8th, 2007 at 3:32 am
Piers,
It is on my to-do list
I am very busy at the moment as can be seen in reducing the frequency of my blog posts.
In the meantime, if there are any specific questions you have feel free to ask.
Regards,
Bruce