16.6. Customizing Object Name Generation

16.6.1. (Insufficient) Object Names
16.6.2. Defining Property Sets
16.6.3. Advanced Property Set Definitions

16.6.1. (Insufficient) Object Names

When recording a test case or picking objects in the Spy, Squish will automatically create a name for the object to identify it. Depending on the configured naming scheme, this name can either be a hierarchical name or a so-called multiple property name. The latter is a set of <propertyName>=<value> pairs enclosed in curly braces. For instance, a multiple property name which identifies the object whose type is Button and whose text is “Hello” looks like

{type='Button' text='Hello'}

Thus, when creating a name for an object, Squish needs to decide which properties to use for identifying the object. However, it can be difficult for Squish to decide on a set of properties which is both

Unambiguous

There mustn't be more than one object in the application which matches the given set of property/value pairs, so that the name identifies just the object you want to.

Minimal

You don't want to have more properties in the object name than necessary so that the name is robust in the face of application changes. For instance, if the object name included all properties of the respective object, any change to the object which affects the value of a property would break the test script since the object name no longer finds the original object.

Squish has a set of heuristics built-in to determine what properties to use, but sometimes this fails. For instance when writing a Qt test, Squish will use the “name” property of objects in the application to identify them if it exists. However, you might find that for your particular application, this is not a good choice since the name is a more or less random value on every run so you would like to remove this property from the list which Squish uses internally.

Starting with Squish 3.2, the property list used to create the real names can be configured by editing some straightforward XML files. How to use these files to customize the name creation process will be explained in the following two sections.

16.6.2. Defining Property Sets

16.6.2.1. Descriptor File Locations

The list of properties used for the real name of some object are defined by XML files. For each wrapper which your application uses there can be up to two XML files (so called “descriptor files”) which have to adhere to a special naming scheme so that Squish finds them:

<Squish_Directory>/etc/<wrapper>_descriptors.xml

This XML file contains the default properties which Squish uses for an object's name. Depending on the type of package you use, you might find qtwrapper_descriptors.xml, swtwrapper_descriptors.xml or others in the etc subdirectory of your Squish installation.

<Squish_Directory> stands for the installation where you installed your Squish package.

<Squish_User_Settings>/<wrapper>_user_descriptors.xml

This file is used for your own extensions. In case you want to modify the default behaviour, either by overriding the existing behaviour or by adding new properties, you can use this file. This XML file contains the default properties which Squish uses for an object's name. Depending on the type of package you use, you might find qtwrapper_descriptors.xml, swtwrapper_descriptors.xml or others in the etc subdirectory of your Squish installation.

<Squish_User_Settings> stands for the directory where user specific settings will be stored. On Windows, this is the directory %APPDATA%\froglogic\Squish, on Unix and Mac OS it's ~/.squish.

In both files, a list of types is defined together with the names of the properties to be used when generating names for objects of that particular type. The file format used to do so is the same in both files and they're treated the same, except that the descriptor file for user extensions (<wrapper>_user_descriptors.xml) can not only add additional type descriptors, but it can also override any descriptors in the main XML file.

16.6.2.2. Descriptor File Format

The list of types and the properties to be used for each object are written down using a rather straightforward XML format. Here's a quick example for some fictive application toolkit which has a Button type:

<objectdescriptors>
  <descriptor>
    <type name="Button">
    <realidentifiers>
      <property>caption</property>
    </realidentifiers>
  </descriptor>
</objectdescriptors>

This descriptor file defines just one descriptor which says that for all objects of type Button, the 'caption' property should be used for the real name.

[Note]Note

This means that not only objects which are instances of the Button class will get the caption property in their real name, but also instances of classes which inherit Button! When deciding which descriptors to use for generating the name for a given object, Squish takes the inheritance hierarchy into account and will use all descriptors whose type name shows up in the inheritance hierarchy of the given object.

In this example, only the name of the type was used for identifying the name. However, it is also possible to introduce so-called constraints which make sure that not all objects of a particular type are applicable but only those which match certain constraints. Another example illustrates this:

<objectdescriptors>
  <descriptor>
    <type name="Button">
      <constraint name="visible">false</constraint>
    </type>
    <realidentifiers>
      <property>caption</property>
      <property>tooltip</property>
    </realidentifiers>
  </descriptor>

  <descriptor>
    <type name="Button"/>
    <realidentifiers>
      <property>caption</property>
      <property>xpos</property>
      <property>ypos</property>
    </realidentifiers>
  </descriptor>
</objectdescriptor>

Here, two descriptors are defined. Both of them are about objects of the Button class, however the first one is only applicable if the 'visible' property of the respective object has the value 'false'. When using this descriptor file to generate the real name for a Button object which is invisible, the properties 'caption' and 'tooltip' will show up in the real name. However, for visible buttons, the second descriptor will be used and hence the properties 'caption', 'xpos' and 'ypos' will be used in the object name.

You could also list more than one constraint. In that case, all of the listed constraints have to match before the descriptor is used. In general, when facing multiple descriptors which all reference the same type name, Squish will try to use the best match; that is, the descriptor with the highest number of constraints of which all match.

16.6.3. Advanced Property Set Definitions

16.6.3.1. The Catch-All Descriptor

In addition to the normal descriptors, which match an object by the type name, there's a special case descriptor which is always used no matter what the name of the object's type is. However, you can use constraints for this special type as well. Here's how to use it:

<objectdescriptors>
  <descriptor>
    <type name="*"/>
    <realidentifiers>
      <property>id</property>
    </realidentifiers>
  </descriptor>

  <descriptor>
    <type name="Button"/>
    <realidentifiers>
      <property>caption</property>
    </realidentifiers>
  </descriptor>
</objectdescriptor>

In this example, a catch-all descriptor (which is denoted by using an asterisk as the type name) is defined. This means that for all objects, no matter what their type name is, the id will be used in the property name. If the given object does not have an id property, it will be silently ignored but not trigger an error.

[Note]Note

It does not hurt to list properties in the catch-all descriptor (or any other descriptor, for that matter) which don't exist on some particular object. For instance, even though the catch-all descriptor would be used for any object, that object doesn't have to have an 'id' property. If it doesn't that property will be silently ignored.

The catch-all descriptor is also taken into account when merging multiple descriptors. For instance, if the above example would be used to generate the name for an object of type Button, the properties 'caption' and 'id' would be used in the real name.

16.6.3.2. Groups of Exclusive Properties

Let's say that you have a descriptor file to generate names for your 'Button' widgets like this:

<objectdescriptors>
  <descriptor>
    <type name="Button"/>
    <realidentifiers>
      <property>id</property>
      <property>caption</property>
      <property>text</property>
      <property>enabled</property>
    </realidentifiers>
  </descriptor>
</objectdescriptor>

With this descriptor, the properties 'id', 'caption', 'text' and 'enabled' will be used in the real name of 'Button' objects. However, this might be too much. For instance, even though you do want the 'id' and the 'enabled' property in the real name, you do not need the 'text' property in case a 'caption' is available. The 'text' property should only be used when there is no 'caption' available.

To solve this common problem, you can use so-called property groups. The idea is to put all properties which exclude each other (in this example, the 'caption' and the 'text' properties) into a group. When generating a name, Squish will try one property in the group after the other. As soon as it finds a property which exists on the given object, all other properties in the group are ignored.

Here's how to do that in XML:

<objectdescriptors>
  <descriptor>
    <type name="Button"/>
    <realidentifiers>
      <property>id</property>
      <group>
        <property>caption</property>
        <property>text</property>
      </group>
      <property>enabled</property>
    </realidentifiers>
  </descriptor>
</objectdescriptor>

Now, names for Button objects will either contain the caption of a property or the text - but never both.

16.6.3.3. Object References

One feature of object names in Squish is that they can not only contain property/value pairs but also references to related objects. For instance, it is possible to identify an input field by specifying the label which is next to the input field (such a label is often called the 'buddy' of the input field).

Here's an example object name for a fictive input field which is not only identified by its own properties but also by the buddy label:

{type='LineEdit' size='32' numbersAllowed='false' buddy={type='Label' text='Last Name'}}

Note how the value of the 'buddy' property is really just another object name, nested in the object name of the input field. The only notational difference between normal properties and such object references is that with normal properties (like 'size' in the example above) the value of the property is enclosed in apostrophes. With object references, this is not the case.

Specifying that some property is really a reference to another object in the XML file is quite straightforward:

<objectdescriptors>
  <descriptor>
    <type name="LineEdit"/>
    <realidentifiers>
      <property>type</property>
      <property>size</property>
      <property>numbersAllowed</property>
      <object>buddy</object>
    </realidentifiers>
  </descriptor>
</objectdescriptor>

The only difference with the buddy property is that it's enclosed in 'object' tags instead of the normal 'property' tags.