Component recognition

The process of identifying components in the SUT during a test run is rather complicated. The problem is that QF-Test has to be extremely flexible in order to accommodate a wide range of applications and to allow for a certain amount of change in the GUI of the SUT, due to dynamic behavior or changes between different versions of the SUT, while still being able to find the component intended by the developer of the test-suite.

This process can be simplified - and its reliability improved considerably - by defining unique names for most of the "interesting" components of the SUT. This has to be done by the developer of the application with the Java method setName(String). If you can get your developers to set unique names for your components or windows, you won't have any problems with component recognition. Even drastic changes in the GUI can be handled if names are being used. Another advantage is that the name is language-independent, so you can use one and the same test-suite to test applications that support different languages. To ease the process of assigning names, QF-Test has a function to suggest names for those components where a name will improve testability. See the option Hotkey for components for further information.

To determine the target component for an event, QF-Test calculates match probabilities for the components of the SUT. The component with the highest probability is used, provided that probability is higher than a configurable bound. First the probabilities for the known windows are determined. Then the search continues among the components of the windows with sufficient probability.

This process is repeated for every hierarchy level of the component, meaning each direct or indirect parent node of the 'Component' node, but working from top to bottom. At every level all components matching the 'Class name' attribute are ordered by decreasing probability and then searched for the component on the next hierarchy level. Components that aren't visible are not considered.

The probability of a component is calculated as follows:

  • Each component starts with a probability of 99%. If geometry information is available, deviations in position or size lead to a probability reduction.
  • Then follow three tests that may either be skipped if no info is given, succeed or fail. A skipped test doesn't change the probability, a failed test reduces it below a given value, while a successful test raises it above another given value.
  • The first test is structural and applies only to 'Component', not to 'Windows'. All components within the currently searched parent container, whose class is the same as or derived of the given 'Class name', are collected in a list (including invisible components). Then the 'Class count' is compared to the size of the list and the 'Class index' must match the position of the component in the list.
  • The next test is for a 'Feature' match, possibly including tests for 'Extra features'. If an 'Extra feature' check of type 'must match' fails, the component is discarded.
  • Finally the 'Name' is tested. The facts that this is the final test and that the bonus and penalty values for this test default to the highest and lowest values, makes this the deciding test, but only if a name is given.

For dialogs there's an additional step to test its modality. Typically a dialog is either modal or non-modal, so by default a modal mismatch prevents recognition. However, sometimes the same dialog may be modal or non-modal depending on the context. If your SUT contains such a dialog, adjust the modal penalty to some value above the minimum value for component recognition.

If the final probability doesn't reach the minimum value, the component is discarded. Finally the component with the highest probability is used. If the component used had a structure, feature or name mismatch, a message is written to the run-log, since this indicates that it may not be the right component after all. Most of the time this is just a sign that the SUT has changed slightly and the components should be updated before too many changes accumulate and start confusing the identification process.

Though this process is already dominated by the 'Name' attribute, you can attach even more importance to it by setting the options Name override mode (replay) and Name override mode (record) to "Override everything". In that case QF-Test simplifies the search for a component by skipping the intermediate containers and going straight from the window to the component with the given name and class. The big advantage of this approach is, that the component will still be recognized, even if you introduce a new container in between the window and the component. The prerequisite for using this method is that you can guarantee that if a name is set on a component, it is going to be unique among the simultaneously visible components of the same class in one window.

If this kind of uniqueness is not possible, the next best setting for these options is "Hierarchical resolution". It requires that components with identical names at least have differently named ancestors. This setting still retains most of the advantages and flexibility of names but in this case recognition will break if a named component is moved from its parent to a differently named parent.