XML is important for Rational Functional Tester users for two reasons. First, data is now frequently formulated in an XML format, either for persistence in a file, a database, or to be sent (usually via HTTP) to another application. Verifying the data content of XMLs is often an important software quality task. So, parsing XMLs to capture data to compare it to baseline data is a common software testing need. Second, Rational Functional Tester employs the XML format to persist its own data. This chapter doesn’t discuss the details of Rational Functional Tester’s use of XML; rather, it covers all of the core XML-handling tasks that are needed to test XML data and to manipulate Rational Functional Tester XMLs.

Handling XML in Rational Functional Tester

This chapter uses a simple sample XML, but one that demonstrates all the basic moves you’ll need to make. It follows:

Rational Functional Tester
8.1.0
Rational Performance Tester
8.1.0
Rational Quality Manager
2.0

Our discussion of XML handling in Rational Functional Tester starts with a brief overview of the two main XML-handling standards, DOM (Document Object Model) and SAX (Simple API for XML). Both DOM and SAX are W3C standards; in Java, DOM and SAX are implemented in the org.w3c.dom and org.xml.sax packages. In VB.NET, the System.Xml libraries implement DOM and a SAX-like parser.

DOM and SAX

DOM and SAX are fundamentally different in that the DOM loads and persists an entire XML document in memory (in a tree-structure form), whereas SAX is event-driven, meaning that a SAX parser fires off a sequence of events reflecting XML structure and content as it scans through an XML document. A SAX parser never holds a whole document in memory. You see output from a SAX parser sooner than from a DOM for equal tasks on equal documents because the SAX parser fires off its events as it encounters them during its scan. In the DOM approach, the entire document is parsed and loaded in memory before any processing can occur.

Because of this key difference in structure, the DOM demands more memory than a SAX parser does for an equivalent document. On the other hand, the DOM provides random access to all document nodes at will because they are all in memory. One of the major factors in the choice of which to use is the size and complexity of the largest document that will have to be parsed relative to the available memory. The DOM is most useful when an XML should be persisted in memory for repeated access. SAX is strongest for processing large XMLs quickly for specific data content where it is not necessary to keep the full XML in memory.

A major intersection of test automation and XML is data content. Code to validate the data content of XML documents is mostly what you need to write, and the most direct route to this is through the DOM. The issue is not that data content can’t be validated with SAX, but more that the DOM is the path of least resistance; the code to extract the data is simpler. So, if your XMLs do not eat up too much memory, or they are not large enough to put you in the slow processing regime, DOM is the easiest route to go. If you are parsing large documents, then SAX becomes an attractive choice.

Properties cannot only be read using getProperty(), but they can be changed using setProperty():

public void setProperty( String propertyName, Object propertyValue )

Although you most likely will not use setProperty() nearly as often as you use getProperty(), it is a method worth knowing about. SetProperty() takes two arguments: the property to change and the value to change the property to.

The reference example is one that involves setting data field values in test objects (for example, text fields). In general, you should use inputKeys() or inputChars() to enter data into the SUT. With some cases, however, this becomes challenging. One such context is internationalization testing. inputKeys() and inputChars() can enter characters only in the current keyboard’s character set. If the current keyboard is set to English, for example, RFT throws a StringNotInCodePageException if your script attempts to enter any nonEnglish characters.

One potentially viable solution is to use setProperty() instead of inputKeys() to set the field value. The first step is to determine the property you need to set. Manually set a value, and then examine the test object using either the Inspector or the Verification Point and Action Wizard. Search for a property whose value is the data value you entered. If you enter a search term of Pasta Norma in a Google search field and examine the field with the Inspector, you see two properties whose values are Pasta Norma: value and .value. This is not uncommon: It’s possible that the data value is represented by more than one property. It’s a good idea to note all these property names because some might be read-only. If you try to set a property value that’s read-only, Rational Functional Tester throws an exception.

If you had a datapool with different search strings in different character sets, you can manipulate the scripts to perform multiple searches, as shown below.

Using SetProperty() to set data in a test object

Java


while (!dpDone()) {
text_q().setProperty(".value", dpString("SearchItem"));
// Do what we need to do
dpNext();
}

VB.NET


Do until(dpDone())
text_q.SetProperty(".value", dpString("SearchItem"))
' Do what we need to do
dpNext()
loop

Why Is InputKeys() Preferred?

To illustrate why inputKeys() is the preferred method to enter data into objects, test what happens if you set the quantity of CDs to buy in the Classics sample application:

quantityText().setProperty("Text", "4");

You see something odd happen (or, not happen in this case): The total amount is not updated to reflect the new value. The reason for this is that the total amount is updated when the inputKeys event is fired. setProperty() does not cause this event to fire and is therefore not a possible technique to set the quantity field.

In addition to the flexibility of being able to use datapool references in verification points created with the Rational Functional Tester Verification Point Wizard, you can create your own dynamic verification points in code. RationalTestScript (the root of all script classes) has a method, vpManual(), which you can use to create verification points.

vpManual() is used when you want your script to do all the work of verifying data. That work consists of capturing expected data, capturing actual data, comparing actual data with expected data, and logging the results of the comparison. Think of manual as referring to manual coding.

This discussion begins with the first signature (which you will likely use most often). In vpManual’s three-argument version, you supply a name for your verification point along with the baseline and actual data associated with the verification point. vpManual() then creates and returns a reference to an object; specifically, one that implements Rational Functional Tester’s IFtVerificationPoint interface. The verification point metadata (name, expected, and actual data) are stored in the returned IFtVerificationPoint.

IFtVerificationPoint myVP = vpManual( "FirstName", "Sasha", "Pasha");
Dim myVP as IFtVerificationPoint = vpManual( "FirstName", "Sasha", "Pasha" )

There are a couple of items to note about using vpManual():

* vpName— The verification point name must be a script-unique valid Java (or .net) method name and be less than 30 (.net) or 75 (Java) characters.
* Baseline and Actual data— The compiler accepts a reference to anything that inherits from Object (which means that in .NET, any argument you pass is acceptable; Java allows anything other than primitives, such as int, bool, and so on); however, you need to satisfy more than the compiler. To automate the comparison of baseline with actual data, you need to pass data types that Rational Functional Tester knows how to compare (you don’t want to have to build your own compare method). This limits you to passing value classes. Some examples of legal value classes are: any data returned by getTestData(), strings, primitives, wrapper classes (Integer, Boolean, and so on), common classes that consist of value class fields (for example, Background, Color, Bounds, ITestData, meaning, anything returned by getTestData()), and arrays (one and two-dimensional), vectors, and hashtables that contain value class elements.

What do you do with the IFtVerificationPoint that vpManual() returns? In the simplest case, you call performTest() and get on with things. performTest() compares the baseline with the actual and logs the results (boolean) of the comparison.

A simple comparison

Java

IFtVerificationPoint myVP = vpManual( "FirstName", "Sasha", "Pasha");
boolean passed = myVP.performTest();

VB.NET

Dim myVP As IFtVerificationPoint = VpManual("FirstName", "Sasha", _ "Pasha")
Dim passed As Boolean = myVP.PerformTest

In two lines of code, you have done quite a bit. You created a verification point and compared and logged the results of comparing the baseline to the actual data. It’s common to combine these two statements into one:

vpManual( "FirstName", "Minsk", "Pinsk").performTest();

You use this style when the only method you need to invoke on the IFtVerificationPoint returned by vpManual() is performTest().

It’s important to note that the three-argument version of vpManual() does not persist baseline data to the file system for future runs. It’s also important to stress the importance of the uniqueness of the name in the script.

To illustrate how Rational Functional Tester behaves when a verification point is not unique, consider the simple example where vpManual is called in a loop (demonstrated in below code). The loop in each code sample simply compares two numbers. To introduce some variety, you force the actual value to equal the baseline value only when the baseline value is even.

Consequences of a nonunique verification point name

Java

for(int baseline = 1; baseline <= 10; baseline++ ) {
int actual = baseline % 2 == 0 ? baseline : baseline + 1;
vpManual("CompareNumbers", baseline, actual).performTest();
}

VB.NET

For baseline As Integer = 1 To 10
Dim actual As Integer
If (baseline Mod 2 = 0) Then
actual = actual
Else
actual = baseline + 1
End If
VpManual("CompareNumbers", baseline, actual).PerformTest()

Next

If you execute this code, you see two interesting results in the log:
  • The pass/fail status for each verification point is what’s expected (half pass, half fail).

  • The comparator shows the correct actual values for each verification point, but a baseline value of 1 for every verification point. The reason for this is that after an IFtVerificationPoint has been created, the baseline cannot be updated.

The common technique to deal with this issue (in a looping context) is to append a counter to the verification point name, guaranteeing a unique name per iteration. This is shown in below code

Guaranteeing a unique verification point name

Java

for(int baseline = 1; baseline <= 10; baseline++ ) {

int actual = baseline % 2 == 0 ? baseline : baseline + 1;

vpManual("CompareNumbers_" + baseline, baseline,

actual).performTest();

}

VB.NET

For baseline As Integer = 1 To 10

Dim actual As Integer

If (baseline Mod 2 = 0) Then

actual = actual

Else

actual = baseline + 1

End If

VpManual("CompareNumbers_" & baseline, _

baseline, actual).PerformTest()

Next

Persisting Baseline Data

In addition to the three-argument version of vpManual(), there is a two-argument version of vpManual():

IFtVerificationPoint vpManual( String vpName, Object data )

The two-argument version is used when you want to persist the baseline data to the Rational Functional Tester project. Here’s how it works. The first time performTest() is called on an IFtVerificationPoint with a given name (the name passed to vpManual()), no comparison is done. The baseline data is written to the RFT project and a verification point displays in the Script Explorer (and an informational message is written to the log). With each subsequent execution of performTest() on an IFtVerificationPoint with the same name, the data argument passed to vpManual() is treated as actual data, and performTest() executes the comparison, logging the result.

To retrieve the value of a single property, use the getProperty() method in the TestObject class. You can use getProperty() with both value and nonvalue properties. In this section, the discussion is limited to value properties. The signature of getProperty() for Java is:

Object getProperty( String propertyName )

The signature of getProperty() for VB.NET is:

Function GetProperty( propertyName as String) as Object

The argument is the name of the property whose value you want to retrieve. Because getProperty can be used with any value or nonvalue property, the return type is generic Object. You typically want to cast to a specific type (for example, String).

For value properties, you can even use Rational Functional Tester to generate the code for you.

1.Place your cursor at the line in your script where you want the code to generate.
2.Insert recording.
3.Launch the Verification Point and Action Wizard.
4.Click the desired test object.
5.In the Select an Action window, click Get a Specific Property Value.
6.The wizard will then display all the test object’s value property names and values. Click the property you want, and then click Next.
7.In the Variable Name window, enter a variable name to hold the returned value (RFT generates a variable name for you but you will typically always want to change the variable name), and click Finish.

If you selected the label property, Rational Functional Tester generates the following code.

In VB.NET:

Dim buttonLabel As String = PlaceOrder().GetProperty( "label" )

In Java:

String buttonLabel = (String)placeOrder().getProperty( "label" );

In Java, you need to explicitly cast to the correct type. For example, if you retrieve a non-String property value, such as the Background property, you see:

java.awt.Color buttonBackground =
(java.awt.Color)placeOrder().getProperty( "background" );

If you pass a property name that does not exist in the object, Rational Functional Tester throws a PropertyNotFoundException.

As you become more comfortable with Rational Functional Tester, you can rely less on the wizard to generate code for you.