Convert Text-Based Object Maps to Script-Based Object Maps

With Squish 6.4 we introduced script-based object maps, which provide a more powerful way to manage object names. Script-based object maps will enable you to use native script language concepts to organize the object map, to reduce redundancy and to help with dynamic object lookup. In this article I will show you how you can approach converting your existing text based object maps to this new approach. I will highlight some of the challenges you can expect and explain how you can overcome them.

Conversion Utility

If you open a test suite that you want to convert, you can find the conversion utility inside the test suite settings.

Open conversion dialog via suite settings The conversion utility can be found in the suite settings

The basic conversion utility can help you with some of the tedious grunt work, but will most likely require some manual work as well.

Conversion Dialog

The conversion utility The conversion utility

If you open the utility it will give you the option to "Copy & Convert" or to "Convert In-Place". Copy & Convert will make a copy of the test suite before converting it and is the recommended option, because it will prevent data loss. Convert In-Place will overwrite the existing test suite. Furthermore you have the option to preserve the text-based object map. You can use this option to use the text-based and script-based object map side by side. This can help to ease the transition phase.

While using the text-based and script-based object map side by side is also possible in 6.4, the option to preserve the text-based object map on conversion will only be available in 6.4.1. (You can achieve the same by deselecting the object map deletion when you review the changes in the refactoring dialog and by copying over the OBJECTMAP=... entry from the suite.conf)

Conversion process

First the utility will create a script-based object map from your text-based object map. Same as with any newly recorded scripts the converted script-based object map is not optimized yet. While it will work just fine in an unoptimized state, it will neither be more readable or maintainable than a text-based object map. Therefore you should invest some work and use the features of the script language to reduce redundancy and better structure your script-based object map.
In a second step the utility will search and replace all symbolic name occurrences in your test scripts and verification points. Because symbolic names and real names are sometimes used in more complex code constructs this method is a little error prone. Consequently you will have to review the resulting changes manually. We documented some common conversion problems here.
In the last step you can review the changes that will be made by the conversion. Each script file and verification point change will be displayed in a refactoring dialog. Here you can review and deselect changes that are incorrect.

Review and select conversion changes in the refactoring dialog

Depending on whether you chose to keep the text-based object map, right at the bottom of the change list you will find the deletion of the text base object map. In some cases it might make sense to not delete it right away.

Step by Step Conversion

It is possible to use both the text-based and script-based object map side by side. This makes it possible to gradually migrate to the script-based object map. In a first step you could decide to only convert those test scripts that get converted correctly. Those test scripts could then use the new script-based object map while all other test scripts can keep using the existing text-based object map. This way you can keep using your test scripts while you gradually migrate the more complicated scripts.
When you record new scripts, squish will try to reuse as many known names as possible and even in a converted suite that will include text-based names. Therefore if you plan to use this mixed approach you should make sure that newly recorded names do not contain text-based symbolic name references. Otherwise you might increase the dependency of the text-based object map and phasing it out will become more difficult.

Embrace the challenge

While it might involve a lot of manual work to verify and adapt all your test scripts, you should take this as an opportunity to improve your object map and test scripts. Because the areas where the conversion falls short are actually the areas where the script-based object map performs really well and can bring a lot of improvement and stability to your test cases. All places where you have custom real name handling, where the conversion might struggle, can probably be integrated into the script-based object map. This will reduce custom naming logic inside your test script and will hence make them easier to maintain.

Example: How to fix custom real name handling

In test suites with text-based object maps it is very common to parametrize real names to achieve a more dynamic object lookup. In this example the content of a table is compared to a reference data set. To easily access each cell a real name is parametrized through string replacement (which in itself is already not optimal and error prone).
[code language="python" highlight="6-7" title="Custom real name handling example"]dataSet = testData.dataset(dataSetPath);
row = 0
for record in dataSet:
for column in xrange(0,3):
targetValue = testData.field(record, column)
realName = "{column='%s' container=':Address Book - MyAddresses.adr.File_QTableWidget' row='%s' type='QModelIndex'}" % (column, row)
test.compare(waitForObjectExists(realName).text, targetValue)
row = row +1[/code]
Converting this with the conversion utility will yield an incorrect result because the symbolic name reference :Address Book - MyAddresses.adr.File_QTableWidget will be replaced by a dictionary reference which isn't allowed for text-based real names.
[code language="python" highlight="6" title="Incorrect test script conversion result"]dataSet = testData.dataset(dataSetPath);
row = 0
for record in dataSet:
for column in xrange(0,3):
targetValue = testData.field(record, column)
realName = "{column='%s' container=names.address_Book_MyAddresses_adr_File_QTableWidget row='%s' type='QModelIndex'}" % (column, row)
test.compare(waitForObjectExists(realName).text, targetValue)
row = row +1[/code]

To fix this, the dynamic lookup can be moved into the script-based object map and the error prone string replacement can be replaced by simple dictionary operations. This will make the test script much more maintainable. To achieve this we can simply create a function inside the script-based object map and call it from the test script.

[code language="python" title="Manually created function inside script-based object map (names.py)"]def addressTableCell(row, column):
return {"column": column, "container": address_Book_MyAddresses_adr_File_QTableWidget, "row": row, "type": "QModelIndex"}[/code]
[code language="python" highlight="6" title="Manual test script conversion. Calling function instead of complicated real name handling"]dataSet = testData.dataset(dataSetPath);
row = 0
for record in dataSet:
for column in xrange(0,3):
targetValue = testData.field(record, column)
test.compare(waitForObjectExists(names.addressTableCell(row, column)).text, targetValue)
row = row +1[/code]

If you follow this general approach you should be able to already improve your test scripts and object map while migrating to script-based object maps.

Comments

    The Qt Company acquired froglogic GmbH in order to bring the functionality of their market-leading automated testing suite of tools to our comprehensive quality assurance offering.