Splitting An Object Map To Ease Maintenance

Last edited on

The Squish object map is a powerful concept to simplify test maintenance in case the application under test (AUT) changes. However, managing object names can pose to be a real challenge when working with tests exercising complex applications or tests which execute multiple applications concurrently. The following article will discuss two cases in which these issues occur, and how splitting an object map helps mitigating the risk.

Splitting An Object Map

In general, splitting an object map is only viable when using script-based object maps. The idea is to not have a single file (typically called shared/scripts/names.*) holding all object names but rather factoring the names into multiple files and then including them into the central script file.

For instance, given a JavaScript-based object map like

source(findFile("scripts", "javascript/objectmaphelper.js"));

export var itemViewsQTreeView = {"occurrence": 2, "type": "QTreeView", "unnamed": 1, "visible": 1};
export var ingredientsTreeView = {"type": "QTreeView", "name": "ingredients_tv"};
export var snapshotsTreeView = {"type": "QTreeView", "name": "snapshots_tv"};
export var okButton = {"type": "QPushButton", "text": "OK"}
export var cancelButton = {"type": "QPushButton", "text": "Cancel"}
export var retryButton = {"type": "QPushButton", "text": "Retry"}
names.js

we might decide to move all names related to tree controls into a file names_trees.js and all button names into a file called names_buttons.js. We can then reexport both files in the main names.js script:

export * from 'names_trees.js';
export * from 'names_buttons.js';
names.js
export var itemViewsQTreeView = {"occurrence": 2, "type": "QTreeView", "unnamed": 1, "visible": 1};
export var ingredientsTreeView = {"type": "QTreeView", "name": "ingredients_tv"};
export var snapshotsTreeView = {"type": "QTreeView", "name": "snapshots_tv"};
names_trees.js
export var okButton = {"type": "QPushButton", "text": "OK"}
export var cancelButton = {"type": "QPushButton", "text": "Cancel"}
export var retryButton = {"type": "QPushButton", "text": "Retry"}
names_buttons.js

Motivating Case: Keeping Object Map Size Manageable

As the testing effort progresses, test suites typically grow since test cases get added. For all but the most trivial applications, adding test cases means that new script code is added which interacts with new UI controls, resulting in an ever-growing set of object names stored in the object map. Creating a comprehensive set of tests on a complex application such as an Integrated Development Environment (IDE) can require an object map with thousands of entries. This makes maintenance challenging, especially when multiple persons are working on the tests concurrently:

A good strategy to address this issue is to split the object map into multiple conceptual parts. For instance, it might be imaginable to have one separate object map file per dialog of the application. One or more of such parts could then be associated with a person maintaining that object map. This would solve both of the above mentioned issues:

Motivating Case: Decoupling Object Names

However, even smaller object maps can benefit from being split into separate parts. One such case is when creating tests involving multiple applications; Squish script functions such as startApplication or attachToApplication make it easy to create tests which automate multiple applications (potentially running on different computers) in a single test script. A simple example when this is useful is a chat client: to test a chat client, you might devise a behaviour-driven test which looks something like this:

Feature: Sending Messages

    Scenario: Sending messages to a different (compatible) client

        This test verifies that sending a message from our chat client
        to the third party chat client 'FrogChat' works

        Given I launch the chat client on computer 'systemA'
        And I log in as user 'Alice'
        And I launch the FrogChat chat client on computer 'systemB'
        And I log in as user 'Bob'
        When I enter the message 'Hello Bob' into the chat client
        Then I should see the message 'Hello Bob' in the FrogChat chat client

When implementing this test, e.g. by recording the interactions, the object map will get filled not only with object names corresponding to UI controls in our own chat client, but also with object names for UI controls in the third party 'FrogChat' client.

In particular, it can happen that a single object name is used for a control in our own chat client as well as for a similar control in the FrogChat chat client, e.g.

export var okButton = {"type": "QPushButton", "text": "OK"}
names.js

This gui.okButton names matches any object of type 'QPushButton' with the text 'OK'. It's not hard to imagine that objects matching this description exist in either of the two chat clients. And indeed, when recording test scripts, Squish will reuse this object name for either of the two applications.

However, what happens if the caption of the button changes - but only in one of the two chat clients? For instance, the UI design department might decide that 'Ok' is preferable to 'OK'. The okButton name would need to be adjusted - but doing so would break the test since the button in the FrogChat client still uses 'OK' with a capital K.

Splitting the object map such that the object names are grouped by the application to which the referenced object blongs avoids this issue.