Building a GUI test automation framework: Mapping the GUI

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.

Automation Example Testing5 comments