SAFS Component Recognition

Last Updated by Carl Nagle:

One of the issues involved when attempting to use multiple testing tools; or when trying to migrate from one tool to another; is that each tool has devised a unique way of specifying or locating application components.  Some tools, like IBM Rational Robot and Mercury's WinRunner, allow you to specify a simple string that contains information about the target component.  Other tools, like IBM Rational RobotJ/XDE Tester, require that you provide a valid instance of a proxy "TestObject" or a similar component object--or the component itself--in order to perform an action on the component.

This document attempts to explain how the SAFS framework is evolving a standardized mechanism for specifying, locating, and then retrieving these component references for each tool-specific technology. It is important to note that this assumes the tool in use provides an API that allows you to retrieve and examine the component hierarchy of your application.

Goto: The Problem, SAFS Solution, Key Superclasses, A Walk-Thru.

The Problem:

SAFS Solution:

Key Superclasses:

A Walk-Thru:

So how do we get different tools to actually respond to the same type of recognition information? How does a string that works for IBM Rational Robot also work for IBM Rational XDE Tester, or Mercury's WinRunner, or JRex? Well, lets walk through an example.

We have a test record that tells us what window and what component we want to act on:

Now, regardless of the GUI testing tool we plan to use, we setup "standard" recognition strings in our text-based App Map file--the one readable by SAFSMAPS:

Our hypothetical testing tool of choice is "GUITest" by GUISRUS, but this walk-thru applies to any gui testing tool.

GUITest can use component proxies. These are tool-specific objects that relay information and actions to the real application component. The tool provides an Object Map that allows user-defined names for these to be used in our tests. So, "LoginWindow" could be the user-defined name of such an object in the tool-specific Object Map. In our SAFS lingo, the Object Map is just a tool-specific App Map.

We CAN use the Object Map:
The quick GUITest version of AppMap lookup would be to take "LoginWindow" from the test record and retrieve the "LoginWindow" component from the GUITest Object Map. Which is fine if you have a predefined Object Map, if the names of those objects match the names in your tests, and you don't care to use any tool but GUITest. An augmentation of this is to still use a SAFS App Map file to map AppMap names to Object Map names like below:

This can be beneficial if the tool's Object Map names change (shame on them!); or if maintenance in the tool is too difficult.

As mentioned, this means you have to create a tool-specific Object Map. And if the component you want to reference hasn't been captured in the Object Map, then you can't play with it. It is better to not have to make a tool-specific Object Map if we can dynamically find the objects at runtime. And that is where "standard" recognition strings come into play.

We CAN use "standard" Recognition Strings
Instead of making a tool-specific Object Map, and doing this again for every additional tool or platform; let's instead try an App Map with recognition strings and make that work for all tools. For this, we are back to using App Map A shown previously.

To make this work, we implement the Key Subclasses mentioned earlier for our GUITest tool.

A GTDDGUIUtilities or GTApplicationMap function could provide that Object Map lookup mechanism before resorting to the more dynamic lookup mechanism. You can have multiple lookup mechanisms, as shown below in VERY simplified pseudocode with little or no error detection.

The routine first attempts to locate a cached guisrus.guiobj that might have been stored in the current instance of GTTestRecordHelper. While that would be nice, more than likely we are not going to be that lucky. The GTTestRecordHelper may have this cached value reset at the beginning of processing for this new record. So odds are, we will be going down the findMappedParent path provided by our GTApplicationMap instance.

So, we are going to see what it takes to find the LoginWindow using the recognition strings in App Map A. We continue in GTApplicationMap.findMappedParent(). We start in tool-specific code because we are still searching for items stored in a tool-specific manner. But as you will see, we begin the use of predefined functions in superclasses to help locate the desired component.

We can now see how a GuiObjectVector is going to start us down the dynamic search path. Our GTGuiObjectVector subclass has a tool-specific getParentGUIObject() function, but the code will quickly be calling our predefined search algorithm.

As you can see, the generic superclasses will handle most of the algorithm logic that searches for matching components. The tool-specific subclasses mostly provide the information requested about a given object. The object is whatever the tool, or your subclass implementations, needs to use. This could be Strings, or things like Rational GuiTestObjects. The generic algorithm simply passes them along as needed.

The hunt for matching child objects is essentially the same. Once we match the parent window, we ask for arrays of child objects and process those in the same manner. That is, we loop through the children and query your subclasses to provide the necessary information, or the true or false answers.

Reviewing the Rational RobotJ subclass implementations may (or may not?) make this easier to digest. They have the necessary implementation, but they also have additional functions used by the Rational implementation that would not be necessary for other engines.