Implementing a New Verification Point

prevnext

Fundamentals for Implementing a Verification Point


To implement a new verification point, you must implement the following classes:

The following sections describe these classes.


Implementing the Verification Point Class

Your specialized Verification Point class must extend the com.rational.test.vp.VerificationPoint abstract class and implement all the abstract methods within it. For example, if you are implementing a verification point DatabaseVP, use the following code:

public class DatabaseVP extends com.rational.test.vp.VerificationPoint 

Further, your Verification Point class inherits the framework's entire behavior from this abstract base class. For details about this inherited behavior, see Integrating a Verification Point with QualityArchitect.

Your specialized Verification Point class must perform the following tasks:

  1. Define and maintain the metadata that describes the verification to be performed.

  2. Supply a UI that allows a tester to specify the metadata.

  3. Implement constructors that provide the new verification point's name and metadata.

  4. Implement the Rational code factory methods. These framework methods automatically generate source code into a test script and are capable of creating instances of your verification point.

  5. Provide serialization services for the verification point's metadata.


Step 1. Define and Maintain the Metadata

Your verification point must contain member variables and corresponding get/set methods for all attributes necessary to describe the verification point's metadata.

The following example illustrates the use of get/set methods for retrieving and assigning metadata such as a JDBC user ID, password, url, and a SQL statement:

private String sSQL = "";
private String sJDBCuser = "";
private String sJDBCpassword = "";
private String sJDBCdriver = "";
private String sJDBCurl = "";

public String getSQL() { return sSQL; }
public String getJDBCuser() { return sJDBCuser; }
public String getJDBCpassword() { return sJDBCpassword; }
public String getJDBCdriver() { return sJDBCdriver; }
public String getJDBCurl() { return sJDBCurl; }

public void setSQL( String sSQL ) { this.sSQL = sSQL; }
public void setJDBCuser( String sJDBCuser ) 
	 	 { this.sJDBCuser = sJDBCuser; }
public void setJDBCpassword( String sJDBCpassword ) 
	 	 { this.sJDBCpassword = sJDBCpassword; }
public void setJDBCdriver( String sJDBCdriver ) 
	 	 { this.sJDBCdriver = sJDBCdriver; }
public void setJDBCurl( String sJDBCurl ) { this.sJDBCurl = sJDBCurl; } 

Step 2. Supply a UI to Prompt for the Metadata

If a test script executes your verification point, but the verification point's metadata is not completely defined in the datastore, the verification point must run a UI that prompts the tester for the missing metadata. Specifically, you must provide the following features:

The defineVPcallback() method presents the tester with your UI that prompts for the metadata. When the metadata is retrieved, the method populates the verification point's member variables with the metadata values -- for example:

public boolean defineVPcallback()
{
	 // Invoke some UI and populate the class with the VP's definition.
}

Step 3. Implement the Constructors

Implement at least two constructors that use the super keyword to call the constructor of the VerificationPoint base class, as follows:

Both constructors must pass class objects for the following classes that you have implemented:

The verification point framework can then create instances of these classes to store, serialize, capture, display, and compare the data on which your verification point operated. An example of creating instances of these classes to perform the above methods is shown as follows:

public DatabaseVP( String sVPname )
	 {
	 	 super(sVPname, DatabaseVPData.class,
	 	 	 DatabaseVPDataProvider.class, 	 	 	 DatabaseVPDataRenderer.class,
	 	 	 DatabaseVPComparator.class);
	 	 setIsDefined(false);
	 }

public DatabaseVP( String sVPname, String sSQL, String sJDBCuser,
	 	 String sJDBCpassword, String sJDBCdriver, String sJDBCurl )
	 {
	 	 super(sVPname, DatabaseVPData.class,
	 	 	 DatabaseVPDataProvider.class, 	 	 	 DatabaseVPDataRenderer.class,
	 	 	 DatabaseVPComparator.class);
	 	 this.sSQL = sSQL;
	 	 this.sJDBCuser = sJDBCuser;
	 	 this.sJDBCpassword = sJDBCpassword;
	 	 this.sJDBCdriver = sJDBCdriver;
	 	 this.sJDBCurl = sJDBCurl;
	 	 
	 	 if ( sSQL != null && !sSQL.equals("") && sJDBCdriver != null && 
	 	 	 !sJDBCdriver.equals("") && sJDBCurl != null &&
	 	 	 !sJDBCurl.equals(""))
	 	 {
	 	 	 setIsDefined(true);
	 	 }
	 	 else
	 	 {
	 	 	 setIsDefined(false);
	 	 }
	 }

Step 4. Implement the Code Factory Methods to Generate Code

The code factory methods are similar in function to Java Beans in that both provide additional design-time behavior that is integrated with a Java development environment.

If a QualityArchitect user wants to insert your verification point into a generated test script, the QualityArchitect code generator takes the following actions:

  1. Creates an instance of the verification point (by calling the consructor that specifies just the verification point name).

  2. Calls the defineVPcallback() method for the newly created verification point object, presenting the tester with the UI you created to prompt for the verification point's metadata.

  3. After the tester specifies the metadata through the UI, the code generator invokes the code factory methods to produce Java source code. When inserted into the test script, this source code creates a verification point based on the metadata that the tester provided.

For information about how the code generators use the code factory methods, see Integrating a Verification Point with QualityArchitect.

To enable the code generators to insert an instance of your verification point into a test script, implement the following code factory methods:

The code generators call the codeFactory_getPrefix() and codeFactory_setPrefix() methods; you are not required to call them. However, you must call codeFactory_getPrefix() when constructing the externalized variables returned by the codeFactory_getConstructorInvocation() and codeFactory_getExternalizedInputDecl() methods.

If the code generators set a prefix, prepend the prefix to each externalized variable name used with the codeFactory_getConstructorInvocation() and codeFactory_getExternalizedInputDecl() methods. Doing so ensures that externalized variable names in different verification points within the same scope will be unique.

The following example illustrates the use of code factory methods:

public int codeFactory_getNumExternalizedInputs()
	 {
	 	 int iLines = 0;
	 	 
	 	 // At least 6 lines of code, 4 for JDBC connect info, 1 for VP name and 
	 	 // 1 for SQL statement.
	 	 iLines += 6;
	 	 
	 	 if ( getOptions() != 0 )
	 	 {
	 	 	 // If the user set any options, need to add another variable for that.
	 	 	 iLines++; 
	 	 }

	 	 return iLines;
	 }
	 

public String codeFactory_getExternalizedInputDecl( int nInput )
	 {
	 	 String sCode = "";
	 	 String sPrefix = this.codeFactory_getPrefix();
	 	 
	 	 // Out of range request gets an empty string (still valid code...)
	 	 if ( nInput < codeFactory_getNumExternalizedInputs() )
	 	 {
	 	 	 switch ( nInput )
	 	 	 {
	 	 	 	 case 0:
	 	 	 	 	 sCode = "String s" + sPrefix + "JDBCdriver = \"" + sJDBCdriver 
	 	 	 	 	 	 	 	 	 + "\";";
	 	 	 	 	 break;
	 	 	 	 case 1:
	 	 	 	 	 sCode = "String s" + sPrefix + "JDBCurl = \"" + sJDBCurl + "\";";
	 	 	 	 	 break;
	 	 	 	 case 2:
	 	 	 	 	 sCode = "String s" + sPrefix + "JDBCuser = \"" + sJDBCuser 
	 	 	 	 	 	 	 	 	 + "\";";
	 	 	 	 	 break;
	 	 	 	 case 3:
	 	 	 	 	 sCode = "String s" + sPrefix + "JDBCpassword = \"" 
	 	 	 	 	 	 	 	 	 + sJDBCpassword + "\";";
	 	 	 	 	 break;
	 	 	 	 case 4:
	 	 	 	 	 sCode = "String s" + sPrefix + "SQL = \"" + sSQL + "\";";
	 	 	 	 	 break;
	 	 	 	 case 5:
	 	 	 	 	 sCode = "String s" + sPrefix + "VPname = \"" + getVPname() 
	 	 	 	 	 	 	 	 	 + "\";";
	 	 	 	 	 break;
	 	 	 	 case 6:
	 	 	 	 	 sCode = "int i" + sPrefix + "Options = " 
	 	 	 	 	 	 	 	 	 + Integer.toString(getOptions()) + ";";
	 	 	 	 	 break;
	 	 	 	 default:
	 	 	 	 	 sCode = "";
	 	 	 	 	 break;
	 	 	 }
	 	 }
	 	 
	 	 return sCode;
	 }
	 

public String codeFactory_getConstructorInvocation()
	 {
	 	 StringBuffer sCode = new StringBuffer("");
	 	 String sPrefix = this.codeFactory_getPrefix();
	 	 
	 	 sCode.append("DatabaseVP ");
	 	 sCode.append(sPrefix);
	 	 sCode.append(this.getVPname());
	 	 sCode.append(" = new DatabaseVP( \"");
	 	 sCode.append(this.getVPname());
	 	 sCode.append("\", s");
	 	 sCode.append(sPrefix);
	 	 sCode.append("SQL, s");
	 	 sCode.append(sPrefix);
	 	 sCode.append("JDBCuser, s");
	 	 sCode.append(sPrefix);
	 	 sCode.append("JDBCpassword, s");
	 	 sCode.append(sPrefix);
	 	 sCode.append("JDBCdriver, s");
	 	 sCode.append(sPrefix);
	 	 sCode.append("JDBCurl");

	 	 
	 	 if ( this.getOptions() != 0 )
	 	 {
	 	 	 sCode.append(", i");
	 	 	 sCode.append(sPrefix);
	 	 	 sCode.append("Options);");
	 	 }
	 	 else
	 	 	 sCode.append(");");
	 	 	 
	 	 return sCode.toString();

	 }

Step 5. Provide Serialization Services for the Metadata

Implement readFile() and writeFile() methods to serialize verification point metadata.

The metadata file is read by both the Verification Point Data Comparator class and the TestManager comparator software. Currently, the only supported metadata file format is .ini file format.

A future release of QualityArchitect will support custom-built comparators in addition to the TestManager comparator. As a result, you will be able to use any metadata (and data) file format that your custom comparator supports.

When reading and writing your metadata file, store all metadata for your verification point, as well as properties for the additional [Definition] section in the .ini file, as shown in the following example:

public void writeFile(OutputStream out) throws IOException
	 {
	 	 // If there's nothing to write -- don't write anything...
	 	 if ( sJDBCdriver == "" || sJDBCurl == "" || sSQL == "" )
	 	 	 return;
	 	 
	 	 PrintWriter pwOut = new PrintWriter ( new BufferedWriter ( 
	 	 	 new OutputStreamWriter ( out )));
	 	 	 
	 	 // Write out the [Definition] section
	 	 pwOut.println("[Definition]");
	 	 
	 	 // Write the VP name
	 	 pwOut.println("Case ID=" + this.getVPname());
	 	 
	 	 // Write the VP type
	 	 pwOut.println("Type=Object Data");
	 	 
	 	 // Write the data test
	 	 pwOut.println("Data Test=Contents");
	 	 
	 	 // Write the verification method
	 	 if ( (getOptions() & COMPARE_CASEINSENSITIVE) != 0 )
	 	 	 pwOut.println("Verification Method=CaseInsensitive");
	 	 else
	 	 	 pwOut.println("Verification Method=CaseSensitive");
	 	 
	 	 // Write out the DatabaseVP specific section.
	 	 pwOut.println("");
	 	 pwOut.println("[Database VP]");
	 	 
	 	 // Write out the JDBC connect info
	 	 pwOut.println("JDBCdriver=" + sJDBCdriver);
	 	 pwOut.println("JDBCurl=" + sJDBCurl);
	 	 pwOut.println("JDBCuser=" + sJDBCuser);
	 	 pwOut.println("JDBCpassword=" + sJDBCpassword);
	 	 
	 	 // Write out the Select statement
	 	 pwOut.println("SQL=" + sSQL);

	 	 // Flush the output, and close the file.
	 	 pwOut.flush();
	 }

public void readFile(InputStream in) throws IOException
	 {
	 	 try
	 	 {
	 	 	 Hashtable tblINI = CTutil.mapINIfile( in );
	 	 	 if ( tblINI != null )
	 	 	 {
	 	 	 	 String sDef = "Definition";
	 	 	 	 String sDBVP = "Database VP";
	 	 	 	 
	 	 	 	 // Read out all the entries we care about.
	 	 	 	 String sVerMethod = CTutil.readPrivateProfileString(tblINI, sDef,
	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 "Verification Method");
	 	 	 	 if ( sVerMethod.equals("CaseInsensitive") )
	 	 	 	 	 setOptions(getOptions()|COMPARE_CASEINSENSITIVE);
	 	 	 	 
	 	 	 	 sJDBCdriver = CTutil.readPrivateProfileString(tblINI, sDBVP,
	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 "JDBCdriver");
	 	 	 	 sJDBCurl = CTutil.readPrivateProfileString(tblINI, sDBVP,
	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 "JDBCurl");
	 	 	 	 sJDBCuser = CTutil.readPrivateProfileString(tblINI, sDBVP,
	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 "JDBCuser");
	 	 	 	 sJDBCpassword = CTutil.readPrivateProfileString(tblINI, sDBVP,
	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 "JDBCpassword");
	 	 	 	 sSQL = CTutil.readPrivateProfileString(tblINI, sDBVP, "SQL");
	 	 	 }
	 	 }
	 	 catch ( IOException exc ) { }
	 	 return;
	 }

Implementing the Verification Point Data Class

Your specialized Verification Point Data class must implement the com.rational.test.vp.VerificationPointData interface and perform the following high-level tasks:

  1. Create member variables that encapsulate the data that the verification point is comparing.

  2. Implement readFile() and writeFile() methods to serialize the data to a verification point data file.

  3. Implement the getFileExtension() method.


Step 1. Encapsulate the Data Being Compared

Create member variables that encapsulate the data that the verification point is comparing. The data encapsulated in these member variables should be exposed through public get and set methods that you implement. Doing so allows a test script to create and populate an instance of the class for use in dynamic and manual verification points.

The following example uses the public getData() and setData() methods to encapsulate the data objects being compared:

private String[] asColumns = null;
private Vector vData = null;
	 
public int getNumCols()
{
	 if (asColumns != null )
	 	 return asColumns.length;
	 else
	 	 return 0;
}
	 
public int getNumRows()
{
	 if ( vData != null )
	 	 return vData.size();
	 else
	 	 return 0;
}
	 
public String[] getColumns()
{
	 return asColumns;
}
	 
public void setColumns( String[] asColumns )
{
	 this.asColumns = asColumns;
}
	 
public Vector getData()
{
	 return vData;
}
	 
public void setData( Vector vData )
{
	 this.vData = vData;
}

Step 2. Serialize the Data to a Data File

Implement readFile() and writeFile() methods to serialize verification point data.

The data file is read by both the Verification Point Data Comparator class and the TestManager comparator software. Currently, the only supported data file format is .csv file format.

A future release of QualityArchitect will support custom-built comparators in addition to the TestManager comparator. As a result, you will be able to use any data (and metadata) file format that your custom comparator supports.

The following example illustrates reading from and writing to a .csv file:

public void writeFile(OutputStream out) throws IOException
	 {
	 	 // If there's nothing to write -- don't write anything...
	 	 if ( asColumns == null || vData == null || asColumns.length == 0 )
	 	 	 return;
	 	 
	 	 PrintWriter pwOut = new PrintWriter ( new BufferedWriter ( 
	 	 	 new OutputStreamWriter ( out )));
	 	 
	 	 // First print out a line with all the column names.
	 	 String csvColumns = "";
	 	 int numCols = getNumCols();
	 	 for ( int i=0; i < numCols; i++ )
	 	 {
	 	 	 if ( i > 0 )
	 	 	 	 csvColumns = csvColumns + "," + "\"" + asColumns[i] + "\"";
	 	 	 else
	 	 	 	 csvColumns = "\"" + asColumns[i] + "\"";
	 	 }
	 	 pwOut.println(csvColumns);
	 	 
	 	 // Next print out a line for each element in our vector of data.
	 	 int numRows = getNumRows();
	 	 for ( int i=0; i < numRows; i++ )
	 	 {
	 	 	 Object obj = vData.elementAt(i);
	 	 	 if ( obj != null )
	 	 	 {
	 	 	 	 // Verify that obj is an array of strings 
	 	 	 	 
	 	 	 	 String[] asData = (String[]) obj;
	 	 	 	 if ( asData.length != numCols )
	 	 	 	 {
	 	 	 	 	 // Don't write out this row, and write an error message
	 	 	 	 	 // to the log about the format of this object.
	 	 	 	 	 
	 	 	 	 	 // Log warning message here.
	 	 	 	 }
	 	 	 	 else
	 	 	 	 {
	 	 	 	 	 String csvRow = "";
	 	 	 	 	 for ( int j=0; j < numCols; j++ )
	 	 	 	 	 {
	 	 	 	 	 	 if ( j > 0 )
	 	 	 	 	 	 	 csvRow = csvRow + "," + "\"" + asData[j] + "\"";
	 	 	 	 	 	 else
	 	 	 	 	 	 	 csvRow = "\"" + asData[j] + "\"";
	 	 	 	 	 }
	 	 	 	 	 pwOut.println(csvRow);
	 	 	 	 }
	 	 	 }
	 	 }
	 	 
	 	 // Flush the output.
	 	 pwOut.flush();
	 	 
	 }
	 
	 public void readFile(InputStream in) throws IOException,
	 	 	 	 	 	 	 	 ClassNotFoundException
	 {
	 	 BufferedReader brIn = new BufferedReader ( 
	 	 	 new InputStreamReader ( in ));

	 	 // Read in the array of column names
	 	 String sColumns = brIn.readLine();
	 	 
	 	 // If the file is empty, we're done.
	 	 if ( sColumns == null || sColumns.length() == 0 )
	 	 	 return;
	 	 
	 	 StringBuffer bufCSV = new StringBuffer(sColumns);
	 	 StringBuffer bufElement = new StringBuffer("");
	 	 int numCols = 0;
	 	 boolean bMore = true;
	 	 Vector vColumns = new Vector();
	 	 
	 	 while (bMore == true)
	 	 {
	 	 	 bMore = CTutil.csvGetNextElement(bufCSV, bufElement);
	 	 	 String sElement = bufElement.toString();
	 	 	 
	 	 	 // Remove quotes around string if they are present.
	 	 	 if ( sElement.startsWith("\"") && sElement.endsWith("\"") )
	 	 	 {
	 	 	 	 sElement = sElement.substring(1, sElement.length() - 1);
	 	 	 }
	 	 	 vColumns.addElement(sElement);
	 	 	 numCols++;
	 	 }
	 	 
	 	 // Turn the vector into an array of strings.
	 	 asColumns = (String[])CTutil.toArray(vColumns, new String[1]);
	 	 
	 	 // Now read in all the data lines.
	 	 String sData = "";
	 	 Vector vRow = new Vector();
	 	 vData = new Vector();
	 	 
	 	 for ( sData = brIn.readLine(); sData != null; sData = brIn.readLine() )
	 	 {
	 	 	 bufCSV = new StringBuffer(sData);
	 	 	 bufElement.setLength(0);
	 	 	 int numElements = 0;
	 	 	 bMore = true;
	 	 	 vRow.removeAllElements();

	 	 	 while (bMore == true)
	 	 	 {
	 	 	 	 bMore = CTutil.csvGetNextElement(bufCSV, bufElement);
	 	 	 	 String sElement = bufElement.toString();
	 	 	 	 
	 	 	 	 // Remove quotes around string if they are present.
	 	 	 	 if ( sElement.startsWith("\"") && sElement.endsWith("\"") )
	 	 	 	 {
	 	 	 	 	 sElement = sElement.substring(1, sElement.length() - 1);
	 	 	 	 }
	 	 	 	 vRow.addElement(sElement);
	 	 	 	 numElements++;
	 	 	 }
	 	 	 
	 	 	 if ( numElements == numCols )
	 	 	 {
	 	 	 	 vData.addElement(CTutil.toArray(vRow, new String[1]));
	 	 	 }
	 	 	 else
	 	 	 {
	 	 	 	 // Handle the exception.
	 	 	 }
	 	 }
	 }

Step 3. Provide the Extension for the Data File

Call getFileExtension() to provide the extension of the data file to the test script.

In this release of QualityArchitect, this method always returns csv. In a future release, the method will return the file extension used by whatever data file format (for example, .csv, .dat, .xml) that you select for the data in your Verification Point Data class.

The verification point framework creates the unique file name and data file passed to the writeFile() and readFile() methods. The getFileExtension() method tells the framework what file extension to use, as shown in the following example:

public String getFileExtension()
{
	 return "csv";
}

Implementing the Verification Point Data Comparator Class

Your specialized Verification Point Data Comparator class must implement the com.rational.test.vp.VerificationPointDataComparator interface.

The only method in this interface is compare(). This method compares an expected data object with an actual data object (both of type VerificationPointData) and determines whether the test passes or fails.

The following example illustrates a comparison of two data objects:

public boolean compare( VerificationPointData vpdExpected, 
	 	 	 	 	 	 	 VerificationPointData vpdActual,
	 	 	 	 	 	 	 Object objOptions,
	 	 	 	 	 	 	 StringBuffer sFailureDescription )
	 {
	 	 boolean bIdentical = true;
	 	 StringBuffer bufActual = new StringBuffer();
	 	 StringBuffer bufExpected = new StringBuffer();
	 	 StringBuffer bufFailIndex = new StringBuffer();
	 	 Integer iOptions;

	 	 if ( objOptions != null )
	 	 	 iOptions = (Integer) objOptions;
	 	 else
	 	 	 iOptions = new Integer(0);
	 	 	 
	 	 boolean bCaseInsensitive = (iOptions.intValue() &
	 	 	 	 	 	 	 VerificationPoint.COMPARE_CASEINSENSITIVE) != 0;
	 	 
	 	 DatabaseVPData expected = (DatabaseVPData) vpdExpected;
	 	 DatabaseVPData actual = (DatabaseVPData) vpdActual;
	 	 
	 	 if ( expected.getNumCols() != actual.getNumCols() )
	 	 {
	 	 	 String sText;
	 	 	 if ( expected.getNumCols() == 0 || actual.getNumCols() == 0 )
	 	 	 	 sText = "No column titles";
	 	 	 else	 	 	 	 
	 	 	 	 sText = "Differing number of columns";

	 	 	 sFailureDescription.insert(0, sText);
	 	 	 sFailureDescription.setLength(sText.length());
	 	 	 return false;
	 	 }
	 	 if ( expected.getNumRows() != actual.getNumRows() )
	 	 {
	 	 	 String sText = "Differing number of rows";
	 	 	 sFailureDescription.insert(0, sText);
	 	 	 sFailureDescription.setLength(sText.length());
	 	 	 return false;
	 	 }
	 	 if ( compareStringArray( expected.getColumns(), actual.getColumns(),
	 	 	 	 	 	 	 	 	 	 bCaseInsensitive,	 	 	  bufExpected, bufActual,
	 	 	 	 	 	 	 	 	 	 bufFailIndex) == false )
	 	 {
	 	 	 String sText = "Column title[" + bufFailIndex.toString() + 
	 	 	 	 	 	 	 	 "]: expected[";
	 	 	 sText += bufExpected.toString() + "], actual[" + 
	 	 	 	 	 	 	 	 bufActual.toString() + "].";
	 	 	 sFailureDescription.insert(0, sText);
	 	 	 sFailureDescription.setLength(sText.length());
	 	 	 return false;
	 	 }

	 	 // Walk the vectors of data and compare each row.
	 	 int numRows = expected.getNumRows();
	 	 int numCols = expected.getNumCols();
	 	 Vector vExpected = expected.getData();
	 	 Vector vActual = actual.getData();
	 	 String[] asExpected;
	 	 String[] asActual;

	 	 for ( int i=0; i < numRows; i++ )
	 	 {
	 	 	 Object obj = vExpected.elementAt(i);
	 	 	 asExpected = (String[]) obj;

	 	 	 obj = vActual.elementAt(i);
	 	 	 asActual = (String[]) obj;
	 	 	 	 
	 	 	 if ( compareStringArray( asExpected, asActual, bCaseInsensitive,
	 	 	 	 	 bufExpected,	 	 	 	  bufActual, bufFailIndex ) == false )
	 	 	 {
	 	 	 	 // Row + 2 -> 1 for the column titles (which show up as a row)
	 	 	 	 // and one for 0 index into vector vs. 1 index in grid comparator.
	 	 	 	 String sText = "Difference found in row[" + Integer.toString(i+2);
	 	 	 	 sText += "], column[" + bufFailIndex.toString() + "].";
	 	 	 	 sFailureDescription.insert(0, sText);
	 	 	 	 sFailureDescription.setLength(sText.length());
	 	 	 	 return false;
	 	 	 }
	 	 }
	 	 
	 	 return true;
	 }
	 
	 private boolean compareStringArray( String[] asX, String[] asY, 
	 	 	 	 	 boolean bCaseInsensitive, 	 	 StringBuffer bufFailX, 
	 	 	 	 	 StringBuffer bufFailY, StringBuffer bufFailIndex )
	 {
	 	 if ( asX.length != asY.length )
	 	 	 return false;
	 	 	 
	 	 boolean bDifferent;
	 	 	 
	 	 for ( int i=0; i < asX.length; i++ )
	 	 {
	 	 	 if ( bCaseInsensitive )
	 	 	 	 bDifferent = !asX[i].equalsIgnoreCase(asY[i]);
	 	 	 else
	 	 	 	 bDifferent = !asX[i].equals(asY[i]);
	 	 	 	 
	 	 	 if ( bDifferent )
	 	 	 {
	 	 	 	 bufFailIndex.insert(0, Integer.toString(i+1));
	 	 	 	 bufFailIndex.setLength(Integer.toString(i).length());
	 	 	 	 bufFailX.insert(0, asX[i]);
	 	 	 	 bufFailX.setLength(asX[i].length());
	 	 	 	 bufFailY.insert(0, asY[i]);
	 	 	 	 bufFailY.setLength(asY[i].length());
	 	 	 	 return false;
	 	 	 }
	 	 }
	 	 return true;
	 }

Implementing the Verification Point Data Provider Class

Your specialized Verification Point Data Provider class must implement the com.rational.test.vp.VerificationPointDataProvider interface.

The only method in this interface is captureData(). This method uses the metadata in a VerificationPoint object to construct and populate a VerificationPointData object.

The following example illustrates an implementation of the captureData() method:

public VerificationPointData captureData( java.lang.Object theObject,
	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 VerificationPoint VP )
	 {
	 	 DatabaseVP theVP = (DatabaseVP) VP;
	 	 String sSQL = theVP.getSQL();
	 	 String sJDBCuser = theVP.getJDBCuser();
	 	 String sJDBCpassword = theVP.getJDBCpassword();
	 	 String sJDBCdriver = theVP.getJDBCdriver();
	 	 String sJDBCurl = theVP.getJDBCurl();
	 	 int iOptions = theVP.getOptions();
	 
	 	 Connection con = theVP.getCon();
	 	 Statement stmt = theVP.getStmt();
	 
	 	 DatabaseVPData vpsData = null;
	 	 
	 	 // Capture the data!
	 	 
	 	 if ( con == null || stmt == null )
	 	 {
	 	 	 // Create a JDBC connection and statement
	 	 	 try {
	 	 	 	 Class.forName(sJDBCdriver);

	 	 	 } 
	 	 	 catch(ClassNotFoundException e) {
	 	 	 	 theVP.sFailureDescription = 
	 	 	 	 	 	 	 "Database VP Error: Unable to load driver \""
	 	 	 	 	 	 	 + sJDBCdriver + "\"";
	 	 	 	 theVP.bIsValid = false;
	 	 	 	 return vpsData;
	 	 	 }
	 	 	 try {
	 	 	 	 con = DriverManager.getConnection(sJDBCurl, 	 	 	 	 	 sJDBCuser,
	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 sJDBCpassword);
	 	 	 }
	 	 	 catch(SQLException ex) {
	 	 	 	 theVP.sFailureDescription = 
	 	 	 	 	 "Database VP Error: Unable to Connect, UID = "
	 	 	 	 	 + sJDBCuser + ", PWD = " + sJDBCpassword + ", URL = " 
	 	 	 	 	 + sJDBCurl + ", Error = " + ex.getMessage();
	 	 	 	 theVP.bIsValid = false;
	 	 	 	 return vpsData;
	 	 	 }
	 	 	 try {
	 	 	 	 stmt = con.createStatement();	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 
	 	 	 }
	 	 	 catch(SQLException ex) {
	 	 	 	 theVP.sFailureDescription = 
	 	 	 	 	 	 	 "Database VP Error: Unable to create Statement: " 
	 	 	 	 	 	 	 + ex.getMessage();
	 	 	 	 theVP.bIsValid = false;
	 	 	 	 return vpsData;
	 	 	 }
	 	 }
	 	 
	 	 // Execute the query.
	 	 try {
	 	 	 ResultSet rs = stmt.executeQuery(sSQL);
	 	 	 ResultSetMetaData rsmd = rs.getMetaData();

	 	 	 vpsData = new DatabaseVPData();
	 	 	 int numColumns = rsmd.getColumnCount();
	 	 	 String[] asColumns = new String[numColumns];
	 	 	 
	 	 	 // Build a String array of the Column Names
	 	 	 if ( (iOptions & DatabaseVP.OPTION_TRIM) != 0 )
	 	 	 {
	 	 	 	 for (int i=0; i < numColumns; i++)
	 	 	 	 {
	 	 	 	 	 asColumns[i] = rsmd.getColumnName(i+1).trim();
	 	 	 	 }
	 	 	 }
	 	 	 else
	 	 	 {
	 	 	 	 for (int i=0; i < numColumns; i++)
	 	 	 	 {
	 	 	 	 	 asColumns[i] = rsmd.getColumnName(i+1);
	 	 	 	 }
	 	 	 }
	 	 	 
	 	 	 // Put the column data into the VPdata object
	 	 	 vpsData.setColumns(asColumns);
	 	 	 
	 	 	 // Build a Vector of the data elements
	 	 	 Vector vData = new Vector();
	 	 	 int numRows = 0;
	 	 	 try {
	 	 	 	 while( rs.next() )
	 	 	 	 {
	 	 	 	 	 String[] asData = new String[numColumns];
	 	 	 	 	 if ( (iOptions & DatabaseVP.OPTION_TRIM) != 0 )
	 	 	 	 	 {
	 	 	 	 	 	 for (int j=0; j < numColumns; j++)
	 	 	 	 	 	 {
	 	 	 	 	 	 	 asData[j] = rs.getString(j+1).trim();
	 	 	 	 	 	 }
	 	 	 	 	 }
	 	 	 	 	 else
	 	 	 	 	 {
	 	 	 	 	 	 for (int j=0; j < numColumns; j++)
	 	 	 	 	 	 {
	 	 	 	 	 	 	 asData[j] = rs.getString(j+1);
	 	 	 	 	 	 }
	 	 	 	 	 }
	 	 	 	 	 
	 	 	 	 	 // Put the array of strings into the vector at this row's 	 
	 	 	 	 	 index.
	 	 	 	 	 vData.addElement((Object) asData);
	 	 	 	 	 numRows++;
	 	 	 	 }
	 	 	 }
	 	 	 catch(SQLException ex) {
	 	 	 	 theVP.sFailureDescription = 
	 	 	 	 	 	 "Database VP Error: Unable to walk ResultSet.  " 
	 	 	 	 	 	 + "Error = " + ex.getMessage();
	 	 	 	 theVP.bIsValid = false;
	 	 	 	 return null;
	 	 	 }
	 	 	 vpsData.setData(vData);
	 	 }
	 	 catch(SQLException ex) {
	 	 	 theVP.sFailureDescription = 
	 	 	 	 	 	 "Database VP Error: Unable to execute Query \"" 
	 	 	 	 	 	 + sSQL + "\", Error = " + ex.getMessage();
	 	 	 theVP.bIsValid = false;
	 	 	 return vpsData;
	 	 }
	 	 
	 	 return vpsData;
	 }

Implementing the Verification Point Data Renderer Class

Your specialized Verification Point Data Renderer class must implement the com.rational.test.vp.VerificationPointDataRenderer interface.

The only method in this interface is displayAndValidateData(). This method:

The verification point framework invokes displayAndValidateData() when both of the following conditions apply:

When both of these conditions exist, the framework captures the baseline data object and then invokes displayAndValidateData() to display the baseline data. The tester accepts or rejects the data:

In the following example, displayAndValidateData() presents the baseline data object vpdData to the tester for verification:

public boolean displayAndValidateData( VerificationPointData vpdData )
{
	 // Pop up some UI which displays the vpdData object and prompts the
	 // user to accept or reject.

	 if ( bAccepted )
	 	 return true;
	 else
	 	 return false;
}

prevnext


Rational Test Script Services for Java Rational Software Corporation
Copyright (c) 2003, Rational Software Corporation http://www.rational.com
support@rational.com
info@rational.com