簡介:新版本的 IBM® Rational® 測試工具關注於使非程序員也能 更輕松地使用這些工具。本文探討了從一個 Java 程序員的視角出發,如何來編 寫針對 IBM Rational Performance Tester 產品的定制代碼,並在其中利用 Java 語言的面向對象特性,並基於 Eclipse 來實現。
基於 Eclipse 的 IBM® Rational® 測試產品的可擴展能力,特別是 Rational Performance Tester 和 Rational Functional Tester 可以使用 Java™ 編寫定制代碼,使之成為開發復雜和靈活測試程序的明智選擇。
Rational Functional Tester 在用於基於 Web 或者 Java 的應用程序時 ,是一種更加面向 Java 的測試工具,測試腳本會直接以 Java 生成,並提供對 客戶端程序內部 Java 對象的直接訪問。Rational Functional Tester 為更便捷 的擴展性提供了一個內構的模型,使用 SuperHelper 類來擴展 Helper。擴展 Rational Functional Tester 的各種范例,可以在 developerWorks® Rational® 專區中找到。
由於性能測試方面存在的差異,相似的內構 類擴展功能並不存在於 Rational Performance Tester 中,與功能性測試和執行 相反。例如,客戶對象映射並不是性能測試模型的關鍵構件。另外,性能測試被 設計成生成盡可能少的負荷,所以並不會產生冗繁的結果。
本文討論了兩 個潛在的區域,該區域為 Rational Performance Tester 提供了強大的擴展點: 通過一個超類來進行對象擴展,以及通過靜態的方法來使用可再用設施。本文中 的范例為性能測試之間持續性的變量,使用了一種不用編碼的執行方法,非程序 員可以很輕松地重復利用這些變量,非程序員可能會記錄測試或者運行測試場景 。
本文中的范例使用基於 Windows® 平台的 Rational Performance Tester,並采用默認設置。這裡所討論的功能在不同的平台之間不應該有所差異 。本文中並沒有涉及 Rational Functional Tester 的定制代碼問題。
定 制代碼環境
假設您閱讀了本文,並且熟悉 Rational Performance Tester 機制,以添加定制代碼,並查找潛在的改善機會。其他的關於向測試添加定制代 碼的信息(許多其他的 Rational Performance Tester 相關話題)可以在 IBM Redbooks® 發布的“使用 Rational Performance Tester V7”一 文中找到,您可以從 IBM Redbooks 站點中找到。本書中的許多內容同樣適用於 RPT V8 版本。
通用的代碼執行
在繼續深入定制之前,讓我們快速 地查看一下 Java 代碼執行的問題。Rational Performance Tester 按默認的定 制代碼構件來使用項目中的 src 文件夾,它位於一個名為 test 的包中。這個包 中也是從 其他 Rational Performance Tester 構件動態生成 Java 的位置,例 如測試和日程安排。
本文中的范例以一種更加結構化的格式來處理代碼, 以將通用的代碼與動態生成的代碼隔離開來。基本的 src 文件夾,是一個標准的 Java 項目命名規則,仍然作為根來使用。
為了與更加普通的業界標准保 持一致,在這個執行中定義的包可以概括到表 1 中。
表 1. 本文中的 RPT 包
包的名字 描述 com.ibm.rpt.template 包含模板文件的包 com.ibm.rpt.util 包含靈活可再用 Java 類的包 com.yourco.example.var 與本文中描述的范例相關 的范例包
為該執行的安裝或者擴展使用一個相類似 的命名規則。例如:
yourSuffix.yourCompanyName.applicationName.var
< p>位於:
yourSuffix 就是公司標示符的後綴;例如,來自 ibm.com 的 com。yourCompanyName 就是您所在公司的名稱。
applicationName 就是 與變量相關程序的名字,在這些例子中就是 sample。
var 是一個常量, 它指示了與變量相關的包。
提取范例
本文中含有一個包含代碼、 模板以及范例目錄結構的 ZIP (rpt_ext.zip)文件,以及范例的目錄結構。將 ZIP 文件復制到項目工作區內的src文件夾中並提取出內容。您會看到一個與如圖 1 中所示相似的結構。
圖 1. 范例的目錄結構
因為您已經步入了 Java 編程的王國,切換至 Java 透視圖並使用 Package Explorer 視圖來查看布局。您會看到接下來的模板以及設施程序,以及 一個名為 com.yourco.example.var 的空包。正如前面描述的那樣,test 包是所 有 Rational Performance Tester 生成的 Java 文件的默認位置。
圖 2. Java 透視圖 Package Explorer 視圖
testsA 測試中的變量持續性通常包含了動態生成的值,盡管數據源中 或者其他形式數據外部化沒有包含合適的後續對象,它們仍然需要保留到最後的 測試階段。
Rational Performance Tester 使用 IDataArea 類來保留這 些值,它可以得到實例化,並在虛擬的用戶層次上進行訪問,確保數據沒有錯誤 。
向測試插入定制代碼的問題就是 Arguments 區域,只允許通過的值, 而且沒有提供名字關系。
為了解決這個問題,為您需要保存的每一個變量 創建一個單獨的類,給類命的名要參考在隨後的測試中您需要應用的變量名。然 後定義變量的腳本就可以訪問一個普通的 Java 類(在本文中,是 VariablePersister.java),以執行持續性函數。
這種設計的一種好處, 在於如果變量必須更改的話,那麼每一個變量都可以得到擴展,這就使得變量得 到顯著的增加或者降低。
VariablePersister 執行
變量持續性最 有可能的候選對象,是一個簡單的字符串值。這個部分描述了怎樣長久化一個帶 有提供模板的字符串值。不需要代碼更改。
您並不需要成為一個 Java 程 序員,以使用這裡提供的 VariablePersister 執行,但是如果您熟悉定制代碼的 話,理解起來會更加的方便。
為了演示一個簡單的 VariablePersister 用法,會記錄一個隨機生成的詞(來自 http:// www.merriam-webster.com/ 的 現代詞)並保存。然後詞語會翻譯為其他的語言(通過 http://babelfish.yahoo.com/ 的 Yahoo! Babel Fish 進行翻譯)。
創 建一個 VariablePersister 字符串類
確定您處於 Java 透視圖下, Package Explorer 視圖中。
從com.ibm.rpt.template 包中復制 PersistentVariableStringTemplate.java 文件,並將其粘貼到分配給包含值的 包中(在本例中,就是 com.yourco.example.var 包)。
將文件重命名以 匹配您想要長久使用的變量的名字。為了做到這一點,您可以右擊文件並點擊 Refactor > Rename,如圖 3 所示。
圖 3. 重命名 PersistentVariableStringTemplate.java
將拷貝版本的 Java 模板的名字更改為 SAMPLE_VAR1。
圖 4. 重命名 文件界面
保持其他默認的值不變,然後點擊 Finish。
切換回 Test 視角 。
獲取作為應用的變量
Rational Performance Tester 將會驗證 用作變量的一些潛在值,但是在其他的一些實例中,您需要自己定義它們。在記 錄該場景的頁面中顯示在圖 5 中。
圖 5. 今天的 Merriam-Webster 詞
為了將特定的值定義為一個引用,您可以執行下面的步驟:
打 開來自您剛剛記錄的頁面中的回應:
圖 6. WordOfTheDay 響應
Content 部分如清單 1 所示。
清單 1. WordOfTheDay 內容
[-- Content data is 27,493 characters long.
Press Ctrl+Shift+Space or Ctrl+Left Click here to display it. --]
顯示內容(如上所述),並搜索今天的詞。在這裡 HTML 定 義的條件下,定位合適的實例(<span class="headword">debonair</span>)。引用必須足夠獨特以為未來的 測試做好准備。
右擊定位的文本並選擇 Create Reference。
在左 邊的窗格中,點擊 Test Data Sources 項。選擇 References,並清除 Matching Only。您應該看到新定義的引用值(見於圖 7)。
圖 7. WordOfTheDay 數據源
為了對 SAMPLE_VAR1 設置值,您在前面復制的 Java 模板,執行以下 的步驟:
在記錄測試的 Test Contents 區域中,在主 URL 回應條目的下 面,點擊 Insert 並選擇 Custom Code。
圖 8. 插入 WordOfTheDay 定制 代碼
在 Class Name 區域的右邊,輸入 com.yourco.example.var.SAMPLE_VAR1。
點擊 View Code 以確認您的進 入。
點擊 Arguments 框旁邊的 Add,切換至 URl 入口,並點擊您剛剛創 建的引用值。
圖 9. 選擇 WordOfTheDay Arguments
SAMPLE_VAR1 現在已經設置為動態的值,如引用中定義的那樣。
圖 10. WordOfTheDay Test Element 細節內容
通過向 Arguments 區域添加額外的值,您就可以執行相同的程序以創建一個 String[] 數組。在接下來的章節中將會處理這一點。
引用持續性的變量
為了引用來自原始的請求中獲取的值,您可以切換至 URL 定義,會向這 個定義發送一條請求,並檢查 Data 區域以得到合適的值,如圖 11 所示。
圖 11. 持續性的變量值
當測試得到記錄之後,詞 sample 用於獲取請求數據。在 Data 區域內選擇整 個詞 sample,右擊並選擇 Substitute from>Custom Code : com.yourco.example.var.SAMPLE_VAR1。
未來運行的測試將會使用新發現 的值來替換值 sample。
具體的變量持續值
本部分涉及到了簡單 Variable Persister 的免代碼執行,讓我們查看一下這個函數的機制。
注意:
接下來的部分假設您對 Java 編程語言已經很熟悉了。
接 下來的表格列出了包含在三個 Template 類中的 Javadoc 注釋:
這裡是 對來自 Javadoc 代碼范例的描述:
通過虛擬用戶的 IDataArea 持續 RPT 變量的使用。兩個 Constructors 允許簡單字符串值或者任意種類 Objects 的持 續。可以在 com.ibm.rpt.template 包中找到模板。
表 2. 持續性的變量 模板描述
模板文件名 描述 PersistentVariableStringTemplate 簡單的字符串 變量。 PersistentVariableSequentialTemplate 設 置類 String[](數組)的持續性變量,按照它們輸入數組的順序來一次性返回值 。數組會不斷循環直到測試完成為止。 PersistentVariableRandomTemplate 設置類型 String[](數組)的持續性變量,隨機地返回值。
每 一個類都使用包 com.ibm.rpt.util 中的 VariablePersister 類。 VariablePersister 類執行實際的設置並使用 IDataArea 類的 put(String, Object) 和 get(String) 方法來得到定義變量的函數。
首先我們將會查 看一下簡單的類 PersistentVariableStringTemplate,以描述基本的工作。在 超類執行部分中將會討論 Sequential 和 Random 模板。
PersistentVariableStringTemplate 類工作的一個假設是做出了單個字 符串對單個字符串的聯系。在清單 2 中顯示了模板的簡化視圖。
清單 2. 模板代碼范例
public class PersistentVariableStringTemplate implements ICustomCode2 {
// Set the name of the variable key, based on this class name
private final String variableKey = this.getClass ().getSimpleName();
public PersistentVariableStringTemplate() {
}
/**
* The exec(ITestExecutionServices, String[]) Method is the standard
* format for calling Java extension classes from RPT.
*/
public String exec(ITestExecutionServices testExecutionServices, String[] args) {
// Set the initial persisted variable value to null
String variableValue = null;
// Reset the variable variable value if an input value is provided
if (args.length == 1) {
variableValue = args[0];
}
return new VariablePersister(testExecutionServices,
variableKey, variableValue).getVariableValue();
}
}
正如上 面注釋中提到的那樣,定制代碼類的標准運行機制是 exec (ITestExecutionServices,String[]) 方法。在訪問定制代碼時,會通過這些自 動生成的值,ITestExecutionServices 對象會提供關於測試環境的信息,而定制 代碼定義中 String[] 數組就是 Arguments 部分中所列的值。
實際的 VariablePersister 代碼將會由模板文件重新分配為 VariablePersister.java, 它會得到簡單的處理。
程序中代碼的關鍵兩行是:
字符串變量 variableKey 的最終定義,會定義關鍵值的名字,以匹配新分配文件的名字(見 於 VariablePersister Implementation),它用作變量的引用。
這個簡 單的模板假設了單個的值。代碼中執行了確認操作,以確保提供了唯一的論題, 它用作變量值;否則就會返回當前設置的值。該代碼不同於 PersistentVariable Random 和 Sequential Templates,在稍後將會對其作出處理。
對新的 VariablePersister 對象的訪問,會執行剩余的工作,返回與來自 PersistentVariableStringTemplate 文件創建的文件相關的變量的字符串值。
VariablePersister 類被設計成為單個字符串值的實例 :
new VariablePersister(ITestExecutionServices,String, String);
其中的參數是:
testExecutionServices,用於 獲取 IDataArea 的 ITestExecutionServices。
aVariableKey,應用持續 性變量關鍵的名字。
aVariableValue,持續性變量的字符串值。
或者對於一個對象值:
new VariablePersister (ITestExecutionServices,String,Object);
其中的參數是:
testExecutionServices,用於獲取 IDataArea 的 ITestExecutionServices。
aVariableKey,應用持續性變量關鍵的名字。
aVariableContent,持續性值的目標值。
兩個版本的構造方法實 際上都是相類似的,除了存儲值的格式之外,如清單 3 所示。
清單 3. 持續性的代碼
public VariablePersister (ITestExecutionServices testExecutionServices,
String aVariableKey, String aVariableValue) {
// Set variable key/value from input
variableKey = aVariableKey;
// Capture the Virtual User's IDataArea Object from ITestExecutionServices
virtualUserDataArea = testExecutionServices.findDataArea(IDataArea.VIRTUALUSER);
// Set the persisted value if input is provided (aVariableValue)
if (aVariableValue != null) {
variableValue = aVariableValue;
virtualUserDataArea.put (variableKey, variableValue);
} else {
// Try to get current value...
try {
variableValue = (String) virtualUserDataArea.get(variableKey);
} catch (NullPointerException e) {
// No value? Obviously not defined... set to empty String
variableValue = EMPTY_STRING;
virtualUserDataArea.put(variableKey, variableValue);
}
}
}
為了避免 nullPointerExceptions,可使用的方法有:
getVariableValue – 對於字符串值
getVariableContent – 對於對象值
它們分別 返回一個空的字符串值或者一個空的 String[] 數組。
因為這些值都維護 在虛擬用戶的 IDataArea 中,沒有跨用戶值污染的可能性存在。
超類執 行
生成的定制代碼使用一個超類模型,如清單 4 中標准生成的定制代碼 所示。
清單 4. 生成的 RPT 類
package test;
import com.ibm.rational.test.lt.kernel.services.ITestExecutionServices;
public class GeneratedClass implements
com.ibm.rational.test.lt.kernel.custom.ICustomCode2 {
public GeneratedClass() {
}
/**
* For javadoc of ICustomCode2 and ITestExecutionServices interfaces, select
* 'Help Contents' in the Help menu and select 'Extending Rational
* Performance Tester functionality' -> 'Extending test execution with custom
* code'
*/
public String exec(ITestExecutionServices tes, String[] args) {
return null;
}
}
執行的默認超 類是 com.ibm.rational.test.lt.kernel.custom.ICustomCode2。
提供的 兩個基於數組的模板,PersistentVariableRandomTemplate 和 PersistentVariableSequentialTemplate,都擴展了 com.ibm.rpt.util.SuperObject,而它反過來又擴展了 ICustomCode2,提供了一 種內部的位置以運行普通的定制代碼。
SuperObject 類的概念
SuperObject 類中的主要功能,與處理永久性數組變量相關:
序 列數組由 ariablePersister 函數處理,創建一個與 VariablePersister 類相同 名字的變量,該類創建自以 _POINTER 為後綴的模板。對 VariablePersister 類 的每一次訪問,反過來都會訪問 SuperObject 類 getNextPointerValue 方法, 通過 VariablePersister 類中保持數組中的值進行循環。
隨機數組由對 SuperObject 中 getRandomValue(String[]) 方法的調用處理,通過使用靜態方 法容器類 NumericGenerator 中的靜態方法 getRandomInt(int) 中的准隨機數字 生成器。
使用動態生成的數據或者隨機數據,來澄清從測試中使用非相似 數據以進行測試是否可以簡化測試結果的討論。本文並不沒有涉及到這個討論。
SuperObject 類(見於清單 5)以下面的內容開始:
執行 ICustomCode2 類;它的超類
創建一系列的值以支持函數
提供了 一個 exec(ITestExecutionServices, String[]) 方法,以匹配它的超類
清單 5. SuperObject 代碼
package com.ibm.rpt.util;
import com.ibm.rational.test.lt.kernel.IDataArea;
import com.ibm.rational.test.lt.kernel.custom.ICustomCode2;
import com.ibm.rational.test.lt.kernel.services.ITestExecutionServices;
public abstract class SuperObject implements ICustomCode2 {
// definitions for persisted variable array with pointer
public String variableKey;
public String[] variableValue = null;
public String pointerKey;
public Integer pointerValue = null;
// RPT Virtual User definition for ITestExecutionServices
public ITestExecutionServices virtualUserTestExecutionServices;
// RPT Virtual User definition for IDataArea
public IDataArea virtualUserDataArea;
// set Constant values
public static final String POINTER_SUFFIX = "_POINTER";
// required method as part of implementation of ICustomCode2
public String exec (ITestExecutionServices arg0, String[] arg1) {
return null;
}
大多數的後續方法為 VariablePersister 模板提 供了功能。
清單 6. VariablePersister 模板
public public PersistentVariableRandomTemplate() {
}
public String exec(ITestExecutionServices testExecutionServices, String[] args) {
// populate super class (com.ibm.rpt.util.SuperObject) values
virtualUserTestExecutionServices = testExecutionServices;
variableKey = this.getClass().getSimpleName();
pointerKey = variableKey + POINTER_SUFFIX;
// Capture the Virtual User's IDataArea Object from ITestExecutionServices
virtualUserDataArea = virtualUserTestExecutionServices.
findDataArea(IDataArea.VIRTUALUSER);
執行模板代碼可以在超 類的層次上傳播與 ITestExecutionServices 和 IDataArea 對象相關的值。
SuperObject 類中還包含了一個范例日志,如清單 7 所示。
清單 7. 范例日志方法
/**
* <p>Write a message out to the test execution log.</p>
* @param message The String value to be written to the log.
*/
public void putMessage(String message) {
virtualUserTestExecutionServices.getTestLogManager().reportMessage (message);
}
這種方法為對測試日志編寫一條信息提供了 一種快捷的方式,或者以 refactoring 的方式提供了一個值。這可能是一個非必 要的方法,但是它確實演示了提供普通機制的能力。一個更加有用的執行方法可 能是對一個外部的源追蹤特定的事件來使用一個普通的日志,在中央的位置擁有 代碼,會提供簡化的維護與編輯方式。
使用 SuperObject 類
接下 來的范例首先執行了來自 XE.com Universal Currency Converter 的貨幣兌換。 初始的記錄將會將一加元的值轉化為相應的美元值。為了演示 SuperObject 與 PersistentVariableSequentialTemplate 類,會創建一個數組以從網站獲得頂端 的貨幣。
首先,從 PersistentVariableSequentialTemplate 來創建 SAMPLE_VAR2,與對 SAMPLE_VAR1 所做的操作相類似。
在 URL 應用下插 入通用的代碼,並將類設置為 com.yourco.example.var.SAMPLE_VAR2。
圖 12. 貨幣性能測試
為 SAMPLE_VAR2 定制代碼進行 Add,以添加多個值創建一個數組。
圖 13. 選擇貨幣論題
在記錄的測試中擴展對 XE.com Conversion 請求的入口,並選擇 URL www.xe.com/ucc/convert.cgi。
圖 14. 選擇貨幣 URL
將記錄(USD)中第二個貨幣類型值替換為來自 SAMPLE_VAR2 的定制代 碼。
圖 15. 顯示貨幣值
SAMPLE_VAR2 中的定制代碼,將會在測試運行期間通過定義的數組,在值的末 端重新啟動。
與之相類似,PersistentVariableRandomTemplate 可以用 以執行一個隨機訪問的數組。
使用定制代碼中的靜態方法
靜態方 法的使用可能是一種糟糕的面向對象的編程操作。但是,在有些情況下這是達到 目標最快的一種方式。
擴展前面的范例,更改轉化的值,使用一個 com.ibm.rpt.util.NumericGenerator.java 文件中簡單的、可再用的准隨機的數 字生成器。
在初始的 URL 訪問之前添加新的定制代碼,使用一個類名: com.yourco.example.var.SAMPLE_VAR3。點擊 Generate Code。
圖 16. 貨幣轉化
更改 SAMPLE_VAR3 中的代碼:
清單 9. 更改前的代碼
public class SAMPLE_VAR3 extends
com.ibm.rational.test.lt.kernel.custom.ICustomCode2 {
/**
* Instances of this will be created using the no-arg constructor.
*/
public SAMPLE_VAR3() {
}
public String exec(ITestExecutionServices tes, String[] args) {
return null;
}
變更為:
清單 10. 變更後的代碼
public class SAMPLE_VAR3 extends
com.ibm.rpt.util.SuperObject {
/**
* Instances of this will be created using the no-arg constructor.
*/
public SAMPLE_VAR3() {
}
public String exec(ITestExecutionServices tes, String[] args) {
return NumericGenerator.getRandomCurrency("5000");
}
}
NumericGenerator.getRandomCurrency(字符串)方法接受了一 個數字的字符串代表,指示了生成的最高值,反過來提供了一個准隨機的值,它 基於一種貨幣($.¢¢)格式的 DecimalFormat。數字的隨機性使用 java.util.Random 來搜索,反過來又使用來自 System.currentTimeMillis() 的 值來尋找。
清單 11. 生成隨機貨幣的代碼
public static String getRandomCurrency(String high) {
refreshRandom();
double randomDouble =
Math.round(random.nextDouble() * Double.parseDouble(high));
return currencyDecimalFormat.format (randomDouble).toString();
}
private static void refreshRandom() {
random.setSeed(System.currentTimeMillis ());
}
一個錯誤顯示出來,指示 NumericGenerator cannot be resolved。右擊錯誤指示器,並選擇 Quick Fix > Import NumericGenerator(com.ibm.rpt.util)。
圖 17. 錯誤的快速修復
在 www.xe.com/ucc/convert.cgi 的請求數據中,強調顯示位於 Amount= 之 後的 1,並由定制代碼 SAMPLE_VAR3 所取代。1 和 0 之間的准隨機數字將向每 一次測試運行而提供。
分析
本文中提供的范例是簡單的,但是它 們卻顯示了怎樣通過使用 Java 操作來擴展測試功能。降低冗余的代碼,因此減 少了長期的代碼維護費用,通常是一個優秀的目標。
Rational Performance Tester 產品中提供的簡單定制代碼模型,可以輕松地得到擴展,以 使用 Java 超類和再使用的代碼構件來創建一個良好的測試環境。
代碼下載: http://www.ibm.com/developerworks/cn/rational/10/extendingrationalperfo rmancetesterwithjava/