Finding Table Cells by Header Text in Java Applications

Finding Table Cells by Header Text in Java Applications

In another article, we demonstrated how to find table cells by header text in Qt applications. Here, we will show how to do the same thing in a Java AUT (Application Under Test).

Motivation

Finding table cells by header text leads to more readable tests. Furthermore, this is useful if the table columns are not always in a fixed order. With the AddressBook examples, it is possible to reorder the columns, in which case, test cases that refer directly to column numbers may be fragile.

Working with Swing JTable

At record-time, clicking on a table header results in an object being named in the Object Map, of type TableHeaderItemProxy. Instances of this class contain a property called column. This property will change if the table column is reordered. This makes it easy to identify columns by header text. You can see something like the image below from the Squish Spy by picking on one of the table headers and inspecting its properties in the Properties view.

The Object Map entries for TableHeaderItemProxy look something like this:

surname_TableHeaderItemProxy = {"caption": "Surname", "type": "com.froglogic.squish.awt.TableHeaderItemProxy"}
phone_TableHeaderItemProxy = {"caption": "Phone", "type": "com.froglogic.squish.awt.TableHeaderItemProxy"}

Since the caption property was set to something meaningful for these objects, the caption gets picked up and used as part of the symbolic as well as the real names of each TableHeaderItemProxy. These object map entries will work even if the columns are reordered.

However, when recording interactions with the table cells, these TableHeaderItemProxy objects are not used. Instead, we see calls to mouseClick() on the values returned by waitForObjectItem(names.JTable, "x/y"), where the x,y values are fragile.

Given a header text, how can we obtain the column number? With the column property and the scripted Object Map, we can write a helper function that looks like this:

def columnNumber(columnText):
    columnHeaderViewName = {"caption": columnText, "type": "com.froglogic.squish.awt.TableHeaderItemProxy"}
    return waitForObject(columnHeaderViewName).column

Next, we can write a function called tableCell(), which uses this helper function and returns the desired cell, using waitForObjectItem().

def tableCell(columnName, rowNumber):
    colNum = columnNumber(columnName)
    return waitForObjectItem({"type": "javax.swing.JTable", "visible": True}, "{}/{}".format(rowNumber, colNum))

Here is an example test case that tests the functions against the Swing AddressBook example AUT.

def main():
    startApplication("AddressBookSwing.jar")
    activateItem(waitForObjectItem(names.address_Book_JMenuBar, "File"))
    activateItem(waitForObjectItem(names.file_JMenu, "Open…"))
    doubleClick(waitForObjectItem(names.open_JList, "MyAddresses.adr"), 78, 5, 0, Button.Button1)
    # some interactions where columns may be reordered...
    someTableCell = tableCell("Surname", 4)
    test.compare(someTableCell.text, "Boardus")

Working with SWT Table

In SWT, mouse move events on the TableHeader objects are not visible in the SWT event queue. This means the picker can’t pick them, and Squish can’t record interactions like drag and drop on them either. However, you can record a mouseClick() on them to add them to the Object Map, and with the use of Application Objects and tree navigation, it is always possible to find and inspect these objects in question.

The SWTTable has a columnorder property that can be used to determine the current order of the columns, in case they were reordered. To map from column text to current column number, we first need an array of column texts in the original order. This helper function below, getOriginalOrder(), generates that, and should be called once after the Tableis showing all of its columns in the original order.

originalColumns = []
def getOriginalOrder():
    global originalColumns
    originalColumns = []
    table = waitForObject({"type": "org.eclipse.swt.widgets.Table"})
    for i in range(0, table.getColumnCount()):
        tc = table.getColumn(i)
        originalColumns.append(tc.text)

Now we can implement SWT versions of columnNumber() andtableCell() that work like their Swing counterparts:

def columnNumber(columnName):
    global originalColumns
    origidx = originalColumns.index(columnName)
    table = waitForObject({"type": "org.eclipse.swt.widgets.Table"})
    return table.getColumnOrder().at(origidx)

def tableCell(columnName, rowNumber):
    colNum = columnNumber(columnName)
    return waitForObjectItem({"type": "org.eclipse.swt.widgets.Table", visible": True}, "{}/{}".format(rowNumber, colNum))

Conclusion

In the situation where columns are not in a fixed order (or even if they are fixed), using „named columns“ can improve readability and stability in your test cases. This article gives you some ideas on how to achieve this in tests against your Java AUT.

Trainer and Consultant for froglogic. Co-author of "Introduction to Design Patterns in C++ and Qt"

0 Kommentare

Eine Antwort hinterlassen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

*