|
Rational QualityArchitect/Java API Version 1.0 |
|||||||||
PREV PACKAGE NEXT PACKAGE | FRAMES NO FRAMES |
See:
Description
Interface Summary | |
DataTable | A class implementing this interface encapsulates a table of string data. |
VerificationPointComparator | A class implementing this interface provides a method that compares two
VerificationPointData
objects to determine if the comparison succeeds or fails. |
VerificationPointData | A class implementing this interface encapsulates and serializes a single snapshot of either expected or actual data. |
VerificationPointDataProvider | An implementation of this class creates a Verification Point Data object based on the verification point metadata in the specialized Verification Point object. |
VerificationPointDataRenderer | A class implementing this interface provides the capability of displaying the data stored in the Verification Point Data class, allowing the tester to interactively accept or reject that data as the expected (baseline) data for a static verification point. |
Class Summary | |
DatabaseVP | This class implements a database verification point. |
DatabaseVPComparator | The framework
calls the compare() method in this class to compare two
DatabaseVPData objects. |
DatabaseVPData | This class encapsulates and serializes the data being verified by the database verification point. |
DatabaseVPDataProvider | DatabaseVPDataProvider provides the link between the
DatabaseVP class and the DatabaseVPData class. |
DatabaseVPDataRenderer | This class implements a renderer for any class that
implements the DataTable interface. |
VerificationPoint | This class contains the verification point's metadata -- that is, the information that determines the data to capture for this verification point. |
VerificationPointProperties | This class is used to store the Verification Point properties. |
Provides verification point services to Java test scripts.
In functional and component testing, a verification point is a mechanism for testing, or verifying, the state of the component-under-test as a result of one or more operations. For example, in a banking application, you might want to verify that a component correctly calculates a monthly mortgage payment for a given set of inputs such as loan amount, interest rate, and life of loan.
You establish verification points in your test scripts using the classes and interfaces provided in this package. You can use the contents of this package in two ways:
Database...
classes. These are the classes you typically use when writing scripts for EJB testing.
com.rational.test.vp
package.
You implement verification point classes from the abstract verification point framework provided in this package.
database verification point
provided with Rational QualityArchitect plus any verification point types created by the verification point implementer.
Another team member referred to in this package documentation is the tester. The tester is the person who runs the test scripts that the test designer writes.
The following diagram illustrates the different roles of the test team:
A verification point operates on two different types of data:
Data that is known to be correct is called the expected data.
A verification point compares expected data and actual data. If the data matches (or optionally, satisfies some other condition, such as falling within an accepted range), the verification point passes. Otherwise, the verification point fails. Verification point results are automatically logged in the LogViewer.
In the following illustration, the account balance 935.49 is the expected data for a given input (an account number). In three subsequent tests, the stored expected data is compared against the actual data captured during each test. In this example, the verification point passes if the expected data matches the actual data:
The verification point framework contained in this package provides for the three types of verification points summarized below:
Expected Data Object | Actual Data Object | |
---|---|---|
Static Verification Point | Captured when script is first run | Captured at subsequent script runs |
Dynamic Verification Point | Test script passes to verification point | Captured at script runtime |
Manual Verification Point | Test script passes to verification point | Test script passes to verification point |
Static verification points are regression-style tests -- in other words, the successful operation of the component-under-test is implicitly defined by the component's state during an earlier running of the test script, when the captured data was known to be correct.
With static verification points, the expected data object is captured during the first execution of the test script and is stored in the datastore as the baseline for subsequent executions of the test script. The expected data remains persistent unless and until it is explicitly replaced with new expected data.
Each time the test script is subsequently run, an actual data object is captured from the component-under-test. The expected data object is retrieved from the datastore and compared with the actual data captured in the current test run. The results are automatically logged.
Dynamic verification points differ from static verification points in that, with dynamic verification points, the successful operation of the component-under-test is explicitly defined by you, the test script author, not implicitly defined by a previous state of the component-under-test.
With dynamic verification points, the expected data object is passed to the verification point at test runtime. The expected data object is not retrieved from the datastore after having been captured in an earlier execution of the test script, nor is it managed in any way by the verification point framework, as is the case with static verification points.
How the expected data is passed to a verification point is up to you as the author of the test script. For example, you might hard-code the expected data into the script, or supply the expected data through a datapool.
When a dynamic verification point is executed, the expected data object is passed to the verification point's performTest()
method. The verification point then captures the actual data object from the component-under-test, compares the expected and actual data objects, and automatically logs the results.
With manual verification points, both the expected and actual data objects are passed to the verification point's performTest()
method at test runtime. Expected and actual data objects are not provided by the verification point framework, as is the case with static verification points (where the framework provides both expected and actual data objects) and dynamic verification points (where the framework provides actual data objects only).
In other words, with manual verification points, you as the test designer are responsible for providing both the expected and the actual data objects. This frees you from relying on the framework's VerificationPointDataProvider
class to construct objects, allowing you to construct your own objects. The framework simply compares the data objects you provide and logs the results.
The com.rational.test.vp package includes the pre-defined database verification point
for verifying data in a JDBC database. This is typically the verification point you use in writing scipts for EJB testing.
If you need to use other kinds of verification points, the verification point implementer must first extend and implement the class and interfaces in the verification point framework provided in the com.rational.test.vp
package.
The verification point framework contains the following class and interfaces:
VerificationPoint
class
VerificationPointData
interface
VerificationPointDataProvider
interface
VerificationPointDataRenderer
interface
VerificationPointComparator
interface
Conceptually, a verification point is made up of the following classes:
VerificationPoint
abstract class.
This class contains the verification point's metadata -- that is, the information that determines the data to capture for this verification point. Examples of verification point metadata include the list of properties for a user-defined object properties verification point, or connection information and SELECT statements for the JDBC database verification point that is included in this package. This class is also responsible for implementing its own serialization. By requiring your specific verification point implementations to perform their own serialization, all file formats (such as INI, XML, and standard Java serialization) can be supported.
VerificationPointData
interface.
This class encapsulates and serializes a single snapshot of either expected or actual data. An instance of this class can be populated by the captureData
method of a VerificationPointDataProvider
class, or it can be populated manually in the test script -- for example, by literal values or by values from a datapool. Each implementation of the VerificationPointData
interface is required to provide its own serialization methods, once again for support of all possible file formats.
Note: For the current Rational QualityArchitect 0.1 release, Verification Point Data classes must serialize to a .CSV file format. This restriction will be removed in a future release of Rational QualityArchitect.
VerificationPointDataProvider
interface.
This class is a pluggable link between a Verification Point class (which defines a verification point's metadata) and a Verification Point Data class (which stores data for a verification point). Specifically, this class implements the
method to populate a Verification Point Data object for a given Verification Point object.captureData()
VerificationPointDataRenderer
interface. This class provides the capability of displaying the data stored in the Verification Point Data class, allowing the tester to interactively accept or reject that data as a baseline for a static verification point. To enable this capability, the test designer specifies the OPTION_USER_ACKNOWLEDGE_BASELINE
option in the setOptions()
method of the Verification Point class being implemented.
VerificationPointComparator
interface.
This class provides a method to compare two VerificationPointData
objects and determine if the comparison succeeds or fails. The comparison can test for equality between the expected and actual data, or it can test for some other condition (for example, that the actual data falls within a given range).
The following illustration summarizes the verification point classes:
This section outlines the actions that you, the test designer, need to take to set up a verification point in a test script.
Use the actions outlined below as a guideline for setting up a verification point. Other actions may be necessary to accommodate the requirements of a particular verification point implementation.
Note that much of the work that is required to perform a verification point is done for you by the verification point framework.
To set up a static verification point:
The specialized
class encapsulates a verification point's metadata. Metadata includes the following kinds of information:
VerificationPoint
database verification point
includes the SQL statement that retrieves data from a JDBC data source. Or, if you are testing the properties of a component, the names of the particular properties to capture would be specified as metadata.
Verification point metadata can be specified either explicitly or implicitly:
VerificationPoint
class, or it is specified through user-defined set...
methods in the specialized VerificationPoint
class.
Verification points that you record using the Rational QualityArchitect Session Recorder or that you generate through a Rational Rose model are explicitly defined -- that is, the metadata is automatically hard-coded to the constructor.
Note Because explicitly provided metadata can be assigned to test script variables, you can use datapools to supply metadata information to your test scripts.
defineVPcallback()
method. This method runs a user-defined UI that prompts the tester for the metadata information. (The UI is typically developed by the verification point implementer.) After the metadata is captured, the framework writes the metadata to the datastore.
Note Because implicitly provided metadata is retrieved from the datastore rather than being assigned to test script variables, you cannot use datapools with this type of metadata.
For more information about how verification point metadata can be provided, see the
class.
VerificationPoint
To execute a verification point, call the
method in the specialized performTest()
VerificationPoint
class, as follows:
performTest()
method.
null
to the method.
Using the metadata in the specialized VerificationPoint
class, the framework captures the actual data for the test. The framework also checks the datastore for an expected (baseline) data object to compare against the actual data:
However, if no expected data object exists and you have included the OPTION_USER_ACKNOWLEDGE_BASELINE
option in the
method, the framework first invokes an implementer-defined UI that prompts the tester to verifiy that the captured data is correct. If the tester accepts the displayed data as being correct, the framework stores the data object in the datastore as the expected data for subsequent tests. If the tester rejects the displayed data, the framework logs an error, and verification point execution ends. No expected data object is stored.setOptions()
For an example of a static verification point setup in a test script, see Example of a Static Database Verification Point.
Setting up a dynamic verification point is similar to setting up a static verification point. However, before the test script executes the verification point, the test script must create the expected data object. The framework is responsible for capturing and building the actual data object, just as it does for a static verification point.
You create the expected data object using the appropriate implementation of the
interface.VerificationPointData
Once the expected data object is created, you can pass it to the
method when you execute the verification point.performTest()
For an example of a dynamic verification point setup in a test script, see Example of a Dynamic Database Verification Point.
Setting up a manual verification point is similar to setting up a static verification point. However, before the test script executes the verification point, the test script must create both the expected and actual data objects.
You create the expected and actual data objects using the appropriate implementation of the
interface.VerificationPointData
Once the expected and atual data objects are created, you can pass them to the
method when you execute the verification point.performTest()
The verification point framework is built around an open architecture. This open architecture allows you to implement your own verification point types and execute them within the framework.
This section describes the steps necessary to implement a new verification point type. It has the following topics:
This section is intended only for implementers of new verification points. If you are a test designer who is adding existing verification point to your scripts, you can skip this section. This section assumes a sound working knowledge of Java as well as an understanding of verification points.
Note:Some of the examples in this section use the CTutil class to retrieve values from an .ini file. If you want to refer to the CTutil class code for greater understanding of the examples, you can find the code in the section CTutil Class Source Code, which is located in the Rational Test Script Services for Java online documentation.
To implement a new verification point, you must implement the following classes:
The following sections describe these classes.
Your specialized Verification Point class must extend the com.rational.test.vp.VerificationPoint
abstract class, as shown below, and implement all the abstract methods within it.
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 into the QualityArchitect Environment.
Your specialized Verification Point class must perform the following tasks:
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; }
If a test script executes your verification point, but the verification point’s metadata is not in the datastore, the verification point must run a UI that prompts the tester for the metadata. Specifically, you must provide the following features:
defineVPcallback()
method. This is an abstract method of the VerificationPoint
base class.
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. }
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 Verification Point Data, Verification Point Data Provider, Verification Point Data Renderer, and Verification Point Data Comparator classes you have implemented. The framework can then create instances of these classes to store, serialize, capture, display, and compare the data operated on by your verification point — for example:
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); } }
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:
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.
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 into the QualityArchitect Environment.
To enable the code generators to insert an instance of your verification point into a test script, implement the following code factory methods:
codeFactory_getConstructorInvocation()
. This method returns a string of Java code that calls the fully specified constructor of your verification point. Rather than hard-coding the metadata into the constructor call, you should externalize any variables that testers might want to supply with values through a datapool at test runtime.
codeFactory_getNumExternalizedInputs()
. The code generator calls this method to determine how many externalized input variables are present in the constructor call.
codeFactory_getExternalizedInputDecl()
. The code generator calls this method to retrieve each externalized metadata variable.
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(); }
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 Rational 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 the version string? // 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; }
Your specialized Verification Point Data class must implement the com.rational.test.vp.VerificationPointData
interface and perform the following tasks:
readFile()
and writeFile()
methods to perform serialization to a verification point data file.
getFileExtension()
method.
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; }
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 Rational 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. // Llog 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. } } }
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 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 illustrated below:
public String getFileExtension() { return "csv"; }
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; }
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; }
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 displays the data in a VerificationPointData
object and allows the user to accept or reject that data as being correct.
The framework invokes displayAndValidateData()
when both of the following conditions apply:
OPTION_USER_ACKNOWLEDGE_BASELINE
option in the setOptions()
method of the specialized VerificationPoint
class.
When both of these conditions exist, the framework captures the baseline data object and then invokes displayAndValidateData()
to display the baseline data. If the tester accepts the data as being correct, the data is stored as the baseline for the static verification point. If the tester rejects the data, no baseline data is stored for the verification point, and the process is repeated the next time the verification point is executed.
In the following example, displayAndValidateData()
presents the baseline dataobject 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; }
Once you’ve implemented a verification point, integrate the verification point into the QualityArchitect environment. After you do so, testers will be able to insert your verification point into a test script when they generate a test script from a Rational Rose model or when they record a test script with the Session Recorder.
To integrate your verification point with QualityArchitect, perform both of these tasks:
Here is an example of how the database verification point, which is part of the com.rational.test.vp
package provided with QualityArchitect, would be registered in the .ini file:
[Java VP] DatabaseVP = com.rational.test.vp.DatabaseVP
The rqalocvp.ini file is located in the Rational datastore in folder DefaultTestScriptDataStore.
|
30-Jun-2003 | |||||||||
PREV PACKAGE NEXT PACKAGE | FRAMES NO FRAMES |