How to achieve robust component recognition

The most important feature of a GUI test-tool is the recognition of the graphical components. QF-Test offers a lot of configuration capabilities in that area. This chapter gives an overview over the most common strategies and settings to make the component recognition as stable as possible in a project.

We also recommend to take a closer look at section 39.13 and section 45.2.

Note You have to figure out the component recognition strategy before you start utilizing QF-Test for a large testing area in your project. Otherwise you can get into serious troubles in maintaining your tests. Some hints for doing that are described in chapter 32.

Using the default configuration

In most of the projects the default configuration works very well. The default configuration takes the name of a component, its class (type) and also its hierarchy (structure of window) into account for recognizing a component.

You could get troubles using this configuration, if

  • Developers use non-unique names.
  • The component hierarchy changes significantly.
  • Names change significantly (see section 35.4).

If developers do not assign any names, QF-Test uses a combined probability calculation of properties, like the label, the text of a button or the geometry for recognizing a component. That propability calculation is quite good if at least a few properties stay similar over time, e.g. the label text. However, you should ensure that the windows of the SUT are always opened with or resized to the same size.

The default configuration for recording components looks like this:

Figure 35.1:  Default configuration for component recording

The default configuration for recognizing a component during playback looks like this:

Figure 35.2:  Default configuration for component recognition
Using the 'Name overrides everything' mode

If your developers use stable and unique names for all important components which can be accessed by a test, e.g. buttons, tables or text-fields, you can consider changing the configuration to the 'Name overrides everything' mode. This has the advantage that only names of those components and the window they belong to will be used for recognizing the component. Changes to the SUT's component hierarchy will the have no effect on the recognition of those components based on their unique name.

This setting will cause trouble if:

  • Developers use non-unique names.
  • Names are not stable (see section 35.4).

The 'Name overrides everything' configuration for component recording looks like this:

Figure 35.3:  'Name overrides everything' configuration for component recording

The 'Name overrides everything' configuration for recognizing a component during playback looks like this:

Figure 35.4:  'Name overrides everything' configuration for component recognition
Using regular expressions for working with dynamic window titles

Video The Video 'Component recognition' shows the use of regular expressions with windows titles starting from minute 13:07.

In a lot of applications you will face the situation that the developers do not use unique names and QF-Test keeps recording the same components again and again in different places. Playback with previously recorded components may still works unless the window geometry changes significantly.

In this case it is very likely that the title of the main window changes frequently, e.g. to display a version string, a user name, a file name or some other variable information. If you want to keep your tests working and prevent recording multiple variants of this window and all its components, you have to select the respective 'Window' node in the and edit its 'Feature' attribute to replace the dynamic parts of that title with a regular expression. Be sure to check the 'Use regexp' box. Now your tests should work again.

Here you see the use of a regular expression for a component of the JCarConfigurator. Its 'Feature' attribute has to start with 'Edit' followed by an optional dynamic part:

Figure 35.5:  Using a regular expression in the 'Feature' attribute

QF-Test uses regular expressions at many places. You can find detailed information at section 45.4 to learn more about how to use them.

Note QF-Test assigns the 'QF-Test ID' of a component automatically and may use the 'Feature' attribute to generate it like described in section 5.3. The 'QF-Test ID' attribute is an artificial concept for QF-Test's internal use to map actions onto recorded components. Thus it can be pleasing to change it for better readability afterwards. When changing the 'QF-Test ID' QF-Test provides the opportunity to adapt all references automatically.

Influencing the names by implementing a NameResolver

In GUI testing projects you can face a lot of interesting naming concepts. Sometimes the components in an application have no names, but the testers know an algorithm how to name them reliably. Sometimes existing names change from time to time or are completely dynamic, e.g. you can get a name 'button1' after the first recording and after the second recording you get 'button2'. Another situation could be that the current version of the application is part of the name of a dialog window.

In such cases you should take a closer look at the NameResolver interface of QF-Test.

A NameResolver can be used to change or remove names set by developers for the QF-Test perspective. They are only removed for QF-Test not from the real source code.

You can think about utilizing NameResolvers in following cases:

  • The SUT has dynamically changing names.
  • You know a method to set the names uniquely.
  • You want to map names to other names (e.g. due to new versions or for testing other languages.)
  • You want to tune the names of components, e.g. to remove some parts and get nicer QF-Test component IDs in QF-Test.

If you can achieve per-window uniqueness of names with the help of a NameResolver you can also think about switching to the 'Name overrides everything' setting described in section section 35.2.

Note Whenever possible it is preferable that developers set the names directly in their source code as they best know the context of that component. Implementing a NameResolver can become an excruciating task if the developers change the content of the GUI a lot.

NameResolvers are well described in subsection 50.1.6.

Handling classes of components

4.0+QF-Test records so-called generic classes, which means common class names for objects independent of their technical class.

A sample recording for Swing components leads to the generic class Button for any javax.swing.JButton even if you have extended that button class. For other engines you will get a similar recording with the respective classes of that toolkit. In addition this concept allows QF-Test to resolve obfuscated classes without any need to change the default configuration.

During replay QF-Test compares the 'class' attribute of the recorded component with any class of the objects in the SUT. Therefore QF-Test can cope with class changes as long as the standard type isn't changed.

You can find a brief explanation of the generic class concept in section subsection 5.4.1.

Handling class changes due to re-factoring by using 'Record system-classes only'

4.0+ This chapter typically should be relevant just for QF-Test versions older than 4.0 where no generic classes can be used.

By use of this option you can configure QF-Test to record the system base classes of components instead of custom class names. System classes are javax.swing... and java.awt... classes for Java/Swing and org.eclipse.swt.widgets... classes for Java/SWT applications.

Figure 35.6:  Option to configure recording of system classes only

Having just base classes, you will be safe against re-factoring steps of the developers who may change the class structure or rename classes. This option will also protect you from obfuscators which change classes names to protect them against re-engineering.

Having this option active should be helpful in most cases. Only if custom class names are vital for a proper component recognition of components, i.e. if development did not assign useful names but implemented different custom classes for specific containers you might want to consider a deactivation.

3.1+ A mixed approach is also possible by implementing a ClassNameResolver. This can be useful you only want to get system classes for some components, but not all, e.g. when using a third-party library. Please see subsection 50.1.8 for more details.

Avoiding recording every component or using generic components

By now you know how to optimize the component recognition for your needs, but you still have to record every component before you can use it in your tests.

As you can imagine, it can be tiring to record each and every component required for a test. Sometimes this may even become impossible, e.g. when you have changing identifiers or changing labels. A typical situation could be localization testing of an application.

Another situation could be the usage of a GUI framework of your developers. You could have a lot of very similar dialogs, where only some components are different. But you still have to record all parts, which are actually the same, like navigation buttons.

QF-Test offers a feature to reduce the recording of components to a minimum. This concept is called 'Generalizing components'. It consists of making use of variables in the component's details or simply to remove dynamic parts of it.

The general approach for generalizing components is as follows:

  1. Record some components that you want to generalize and compare them.
  2. Create one generic component with an ID, which contains 'generic' so that you can recognize it later.
  3. Remove all attributes that you do not want to use in the recognition in that generic component.
  4. Determine the main properties that you want to use for recognition, e.g. 'Name', 'Feature' or 'Class index'.
  5. Set a variable for the respective attribute, e.g. $(name).
  6. To prevent false positive matches, disable recognition based on geometry by specifying '-' for the 'X' and 'Y' attributes.
  7. Specify '@generic' in the 'Comment' attribute for the generic component to prevent it from inadvertently being removed by the 'Remove unused components' action.
  8. Create a procedure accessing the generic component and use the variable(s) from the previous step as parameter(s).

Note Generic components are very handy for replaying tests, but QF-Test will not use them for recording. You will always get the real component recorded in the test-suite, but can then change the created sequence to make use of the respective generic component.

Switching component recognition settings dynamically

Since QF-Test version 3.1 it is even possible to change component recognition options dynamically. Thus you are very flexible and you can combine different settings for your SUT.

Setting options at runtime can be done via a 'Server script' or 'SUT script' - depending on the option - and calling rc.setOption(OPTION_NAME, OPTION_VALUE). All possible options can be found in section 38.2 for recording and in section 38.3 for replaying tests.