Methods to deal with trees in RFT

Dealing with trees in Rational Functional Tester can be a pain. And there isn’t much good code out there to help. So, I’ve put together a few methods which could serve as a good starting point for you to build your own tree management class. The code isn’t all that efficient, but it’s well commented so you can quickly identify what you may want to change.

I wanted to have a method where I could just pass in a tree object and a regular expression, and RFT would click the right node for me. I also wanted to pass in a regular expression and have the tree navigation path for the matching node returned to me (eg: passing in “Piano” and getting Composers->Mozart->Concerto in D for Piano returned to me…). I also wanted to be able to spit out all the navigation paths of a tree to the console.

What follows is a class called TreeManager, which contains the following methods:

  • getPathForFirstNodeWithRegex
  • clickNodeWithPath
  • clickNodeMatchingRegex
  • printTreeNavigationPaths
  • arrayOfNavigationPaths
  • getPathForAllNodes

With the tree object in the ClassicsJavaA demo mapped as tree2, the result of running the printTreeNavigationPaths method is:

Composers
Composers->Schubert
Composers->Schubert->String Quartets Nos. 4 & 14
Composers->Schubert->Die schone Mullerin, Op. 25
Composers->Schubert->Symphonies Nos. 5 & 9
Composers->Haydn
Composers->Haydn->Symphonies Nos. 99 & 101
Composers->Haydn->Symphonies Nos. 94 & 98
Composers->Haydn->Violin Concertos
Composers->Bach
Composers->Bach->Brandenburg Concertos Nos. 1 & 3
Composers->Bach->Violin Concertos
Composers->Beethoven
Composers->Beethoven->Symphony No. 7
Composers->Beethoven->Symphony No. 9
Composers->Beethoven->Symphony No. 5
Composers->Mozart
Composers->Mozart->Symphony No. 34
Composers->Mozart->Symphony in C, No. 41: Jupiter
Composers->Mozart->Concerto in D for Piano

The results of running System.out.println(getPathForFirstNodeWithRegex("Piano", tree2())); is:
Composers->Mozart->Concerto in D for Piano

Running clickNodeMatchingRegex(tree2(), "Piano"); against the same tree will expand the tree to the Composers->Mozart->Concerto in D for Piano node and click on it.

Useful, huh?

Here’s the code to do all that:

package Scratch;

import resources.Scratch.TreeManagerHelper;

/*
* Copyright (c) 2006, Nathaniel Ritmeyer
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* – Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
* – Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
* – Neither the name of natontesting.com nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/

/*
* www.natontesting.com
*/

//fix up the following two lines of code
//to be correct for your project/class

import com.rational.test.ft.object.interfaces.GuiSubitemTestObject;
import com.rational.test.ft.vp.ITestDataTree;
import com.rational.test.ft.vp.ITestDataTreeNode;
import com.rational.test.ft.vp.impl.ObjectReference;
import com.rational.test.util.regex.Regex;

public class TreeManager extends TreeManagerHelper
{
public void testMain(Object[] args)
{
try
{
//System.out.println(getPathForFirstNodeWithRegex(“Piano”, tree2()));
//printTreeNavigationPaths(tree2());
//clickNodeWithPath(tree2(), “Composers->Mozart->Concerto in D for Piano”);
clickNodeMatchingRegex(tree2(), “Piano”);
}
catch(Exception e)
{
e.printStackTrace();
}
}

/**
* Returns the navigation string for the first node in the tree to
* match the regec
* @param sPattern –the mattern to match the node on
* @param targetTree –the tree to get the details from
* @return The first navigation string in the tree that matches the pattern
* @throws Exception
*/
public static String getPathForFirstNodeWithRegex(String sPattern, GuiSubitemTestObject targetTree) throws Exception
{
//create the regex object that will do the matching for us
Regex rPattern = new Regex(sPattern);

//create a string array to hold all the navigation strings
String myPaths[] = arrayOfNavigationPaths(targetTree);

//loop through each navigation string, starting from the top of the
//tree, and working to the bottom of the tree
for(int i = 0; i < myPaths.length; i++)
{
//if the regex matches the current node…
if(rPattern.matches(myPaths[i]))
{
//return the navigation string for that node
return myPaths[i];
}
}

//if we got here, nothing in the tree matched the regex. Return null
return null;
}

/**
* Clicks on a node in the tree
* @param targetTree –the tree to select the node from
* @param sNodePath –the path of the node
* @throws Exception
*/
public static void clickNodeWithPath(GuiSubitemTestObject targetTree, String sNodePath) throws Exception
{
targetTree.click(atPath(sNodePath));
}

/**
* Click on the first node that matches a regular expression
* @param targetTree –the tree to select the node from
* @param sRegex –the regex to identify the node with
* @throws Exception
*/
public static void clickNodeMatchingRegex(GuiSubitemTestObject targetTree, String sRegex) throws Exception
{
targetTree.click(atPath(getPathForFirstNodeWithRegex(sRegex, targetTree)));
}

/**
* Prints the tree navigation details of all nodes in a tree to the console
* @param targetTree –the tree to get the details from
* @throws Exception
*/
public static void printTreeNavigationPaths(GuiSubitemTestObject targetTree) throws Exception
{
//get the nodes from the tree
ITestDataTreeNode[] nodes = ((ITestDataTree)targetTree.getTestData(“tree”)).getTreeNodes().getRootNodes();

//print the navigation strings for those nodes
System.out.println(TreeManager.getPathForAllNodes(“”, nodes, true));
}

/**
* Returns a string array where each element is a navigation string.
* The array is ordered in the same way that the tree is ordered
* @param targetTree –the tree to get the details from
* @return –String[]
* @throws Exception
*/
private static String[] arrayOfNavigationPaths(GuiSubitemTestObject targetTree) throws Exception
{
//set up array to hold details
String sNavigationPaths[];

//get the nodes from the tree
ITestDataTreeNode[] nodes = ((ITestDataTree)targetTree.getTestData(“tree”)).getTreeNodes().getRootNodes();

//return a string array, based on splitting the results
//string on the newline character
return TreeManager.getPathForAllNodes(“”, nodes, true).split(“\n”);
}

/**
* Iterates through all nodes and figures out the tree navigation path for
* each node.
* @param sPrefix –the current location in the tree
* @param nNodes –the nodes to iterate through (generally, this is just the
* root node of the tree, although beginning halfway up the tree is possible)
* @param isRootNode –pass in “true” if the nNodes being passed in is the
* root node.
* @return — A string containing the navigation path for each node, separated
* by return characters
*/
private static String getPathForAllNodes(String sPrefix, ITestDataTreeNode[] nNodes, boolean isRootNode)
{
//if there are no nodes, return
if(nNodes == null)
{
return “”;
}

//prepare a blank string to contain the result of interogating the node
String sResult= “”;

//loop through each node
for (int index = 0; index < nNodes.length; index++)
{
//get the text value displayed on the node
ObjectReference or = (ObjectReference) nNodes[index].getNode();
String sNodeText = or.getObject().toString();

//decide whether to prefix the node with “->” or not
String sNextLine;
if(isRootNode)
{
//we’re at the root node, don’t prefix
sNextLine = sNodeText;
}
else
{
/*
* we’re not at the root node, we’re at some child somewhere
* prefix the node name with the tree nav so far, and also
* the “->” string…
*/
sNextLine = sPrefix + “->” + sNodeText;
}

//add the navigation line to the results
sResult = sResult + sNextLine + “\n”;

//get the child nodes of the current node
ITestDataTreeNode[] nChildren = nNodes[index].getChildren();

/*
* if the current node has children, recursively call this method,
* passing in the current tree nav path, the child nodes, and “false”
* so that we know that we’re not at the tree root any more
*/
if(nChildren != null)
{
sResult = sResult + getPathForAllNodes(sNextLine, nChildren, false);
}
}

//we’ve finished iterating through the tree; bail!
return sResult;
}
}
As always, please let me know of any improvements/additions you make!

One thought on “Methods to deal with trees in RFT

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>