持續(xù)集成能夠使開發(fā)人員和測試人員在同一個最新的版本上工作。CruiseControl 是現(xiàn)在流行的持續(xù)集成的軟件。自動化測試能夠大大減輕測試人員的工作量,減少測試過程中人為出現(xiàn)的錯誤。STAF (STAX) 是一個輕量級的自動化測試框架。
本文結(jié)合 CruiseControl 和 STAF (STAX) 來介紹一個復(fù)雜環(huán)境下的自動化測試方案。我們使用 CruiseControl 作為自動化測試的入口和調(diào)度器,用它來控制 STAX 任務(wù)的執(zhí)行。STAX 通過 STAX 復(fù)雜對測試代碼進(jìn)行分發(fā)、編譯、部署和測試。在整個測試過程中,我們不僅可以使用 JUnit 測試用例來測試代碼,而且可以使用其他方式的測試用例來測試,比如 Rational Functional Tester 腳本,Robot 腳本等。
本文使用一個簡化了的復(fù)雜應(yīng)用場景作為運(yùn)行自動測試解決方案的環(huán)境。 該應(yīng)用由一個提供簡單 Echo Service 的 WebService 和一個 Web 界面的 WebService 客戶端組成。 用戶既可以使用程序來直接訪問該 WebService 也以通過在瀏覽器中操作該客戶端來訪問 WebService 提供的服務(wù)。在訪問 WebService 和客戶端之前,用戶都需要經(jīng)過身份驗證來聲明自己的身份。
WebService 和客戶端分別運(yùn)行于 Windows 和 Linux 平臺上的 WebSphere 應(yīng)用服務(wù)器之上。在 WebSphere 應(yīng)用服務(wù)器上需要配置登錄認(rèn)證模塊來實現(xiàn)用戶訪問前的身份認(rèn)證。
在這一應(yīng)用場景中,測試團(tuán)隊經(jīng)過分析,對自動化功能測試提出了以下需求:
- WebService 和客戶端需要分別進(jìn)行功能測試。
- 開發(fā)團(tuán)隊提供了用于配置應(yīng)用程序登錄模塊 (LoginModule) 的自動配置部署腳本,該腳本被發(fā)布到一個 FTP 服務(wù)器上。
- WebService 和客戶端的源代碼以及測試腳本的源代碼都存放在 CVS 上,需要在測試執(zhí)行前進(jìn)行自動更新。
- 自動化測試執(zhí)行需要每天自動定時運(yùn)行。
- 測試執(zhí)行的結(jié)果包括執(zhí)行日志需要被測試團(tuán)隊和開發(fā)團(tuán)隊及時訪問到。
針對上述需求,我們可以將這一自動化測試方案分隔為如下圖所示的幾個邏輯組件:
圖 1. 自動化測試方案的邏輯框圖
部署腳本庫是指發(fā)布配置登錄模塊的腳本的服務(wù)器。在本文中,是一個 FTP 服務(wù)器。
源代碼庫是指發(fā)布被測試應(yīng)用程序源代碼以及測試相關(guān)源代碼的服務(wù)器。在本文中,WebService 和客戶端的源代碼以及測試腳本的源代碼都被發(fā)布在一個 CVS 服務(wù)器上。
定時器設(shè)置每天特定時間觸發(fā),本文中,定時器的功能是 CruiseControl 提供的。
自動編譯工具將從源代碼庫中獲取的測試代碼和被測試代碼進(jìn)行編譯。本文中,使用CruiseControl 結(jié)合 Ant 作為自動編譯工具。
測試自動化框架負(fù)責(zé)將編譯完成的被測試代碼和測試代碼部署到測試環(huán)境中,并調(diào)用測試自動化執(zhí)行工具來執(zhí)行測試。在測試執(zhí)行介紹后,框架還需要收集相應(yīng)的執(zhí)行日志,并將執(zhí)行結(jié)果和日志交由 CruiseControl 進(jìn)行發(fā)布,以供測試和開發(fā)人員參考。在本文中,測試框架采用了開源的 STAF、STAX 框架。
測試執(zhí)行工具是指進(jìn)行測試的各種測試工具,本文中,測試工具使用了 JUnit,RFT 等。
測試環(huán)境是指運(yùn)行被測試代碼和測試腳本的環(huán)境。在實際應(yīng)用中測試環(huán)境既可能是一個簡單的Windows 服務(wù)器,也可能是由許多不同平臺,不同類型的服務(wù)器組成的復(fù)雜環(huán)境。本文中,測試環(huán)境包括了不同版本不同平臺的 WebSphere Application Server,以及運(yùn)行測試腳本的一臺服務(wù)器。
測試報表工具是將測試執(zhí)行結(jié)果和日志進(jìn)行呈現(xiàn)的工具。由于測試過程完全自動進(jìn)行,只有將測試結(jié)果和日志盡可能清晰的展示在測試和開發(fā)人員面前,才能充分發(fā)揮自動測試的作用。
從上面對各個邏輯組件的描述中可以看出,測試框架在整個自動化測試方案中位于核心位置。它像控制器一樣管控著其他各個組件,同時又像膠水一樣把各個組件連結(jié)起來協(xié)同工作。
在分析了測試自動化需求和邏輯組件之后,我們可以給出具體的測試方案設(shè)計。
圖 2. 測試方案設(shè)計實現(xiàn)
在上圖中,
控制機(jī)上安裝了 CruiseControl 和 STAF、STAX 框架兩套工具。
編譯機(jī)上安裝了編譯工具 Ant 以及測試執(zhí)行工具 Junit 和 RFT。 其中 JUnit 測試腳本用來測試 WebService,而 RFT 測試腳本則用來測試和操作客戶端。
測試機(jī) 1 和測試機(jī) 2 則分別用來運(yùn)行 WebService 和客戶端。
該測試方案的具體執(zhí)行步驟如下:
- CruiseControl 服務(wù)器在每日指定的時間自動從 CVS 服務(wù)器獲取最新測試代碼,完成后 CruiseControl 服務(wù)器執(zhí)行一個批處理命令來啟動一個 STAF 任務(wù)。
- 該 STAF 任務(wù)從 FTP 服務(wù)器下載最新配置登錄模塊的腳本到本地目錄。
- STAF 將 WebSerivce 和客戶端的源代碼,測試腳本源代碼,以及測試代碼分發(fā)到編譯機(jī)上。
- STAF 在編譯機(jī)上調(diào)用編譯工具 Ant 來編譯被測試代碼(編譯出包含 WebService 的 war 和包含客戶端的 war ),測試腳本源代碼。
- STAF 將編譯出的運(yùn)行時代碼 (war) 通過 WAS 遠(yuǎn)程命令部署到測試機(jī)1,2中。
- STAF 將配置登錄模塊的腳本發(fā)布到測試機(jī)1,2中,并分別在測試機(jī)上運(yùn)行該腳本來配置登錄模塊。
- STAF 在編譯機(jī)上調(diào)用 JUnit 和 RFT 來運(yùn)行測試代碼。
- STAF 將測試結(jié)果送回控制機(jī)并顯示。
STAF/STAX
軟件測試自動化框架( Software Testing Automation Framework,簡稱 STAF )是一個開源的測試自動化框架,它的設(shè)計核心理念是稱為“服務(wù)”的可重用組件(例如,進(jìn)程調(diào)用,資源管理,日志和監(jiān)控等)。 STAX 是構(gòu)建在 STAF,XML 和 Python 語言之上的執(zhí)行引擎,它的出現(xiàn)大大的簡化了測試人員的實現(xiàn)測試自動化的工作。STAX 同時還提供了一個強(qiáng)大的圖形界面監(jiān)控程序,使用該監(jiān)控程序你可以監(jiān)控并控制正在 STAF 框架中執(zhí)行的任務(wù)。
本文STAF/STAX 腳本一章詳細(xì)介紹了在如何使用 STAF/STAX。
CruiseControl
CruiseControl 是一個被廣泛使用的用于軟件持續(xù)集成的開源框架。 所謂軟件的持續(xù)集成( Continuous Integration )是指一種軟件開發(fā)團(tuán)隊頻繁的將他們各自開發(fā)的組件進(jìn)行集成的實踐。通過軟件的持續(xù)集成可以盡早的發(fā)現(xiàn)錯誤,并降低最終集成時所耗費的時間和精力。
本文配置 CruiseControl 一章詳細(xì)介紹了如何配置和使用 CruiseControl。
JUnit/HttpUnit
JUnit 是一個被廣泛使用的用于測試 Java 應(yīng)用程序的開源自動化測試框架。JUnit 提供了十分簡潔易用的編程接口來讓測試人員編寫測試腳本。同時搭配使用 xUnit 系列的工具,JUnit 可以完成對許多不同類型的應(yīng)用的測試。
HttpUnit 是一個專門針對 Web 應(yīng)用程序進(jìn)行自動化測試的開源類庫。它可以模擬瀏覽器的行為(包括表單提交,JavaScript,簡單 http 認(rèn)證,cookie,以及頁面重定向等)來測試 Web 應(yīng)用程序并且允許測試代碼檢查從服務(wù)器端返回的頁面。
在本文中,我們搭配使用 JUnit 和 HTTPUnit 這兩個工具來測試 WebService。
Rational Functional Tester
IBM Rational Functional Tester ( RFT ) 是一個用于進(jìn)行自動化的功能和回歸測試的工具。它使得測試人員可以測試應(yīng)用程序的圖形界面,并提供了數(shù)據(jù)驅(qū)動的測試能力。 RFT 支持不同平臺上的各種類型的圖形界面應(yīng)用,常見的包括在瀏覽器中運(yùn)行的 Web 應(yīng)用界面,用 SWT 開發(fā)的圖形界面等。不僅如此, RFT 還提供了多種語言版本的測試腳本和開發(fā)環(huán)境供測試人員選擇,包括在 Eclipse 環(huán)境中開發(fā) Java 測試腳本和在微軟的 Visio Studio 環(huán)境中開發(fā) VB.net 腳本。RFT 當(dāng)前最新的版本為 7.0。
在本文中,我們使用 RFT 來測試 WebService 客戶端。
本章介紹在自動測試前的準(zhǔn)備工作,包括下列內(nèi)容:
- 配置 WAS 環(huán)境變量,
- 刪除 WAS 上的 JAAS 登錄模塊腳本
- WAS 重啟腳本
- 在部署服務(wù)器上準(zhǔn)備部署腳本
配置 WAS 環(huán)境變量 ( WAS_HOME )
在使用 WAS 開始工作前,首先要配置 WAS 環(huán)境變量 WAS_HOME,WAS_HOME 用于指向 WAS 的安裝目錄。下文中,在使用一些 WAS 自帶的工具時,會引用環(huán)境變量 WAS_HOME 來表示 WAS 的安裝目錄。具體的設(shè)置方法如清單 1 所示。
清單 1. 配置 WAS_HOME
[Windows Platform] set WAS_HOME=C:\Program Files\IBM\AppServer echo %WAS_HOME% [Linux Platform] export WAS_HOME=/opt/IBM/AppServer echo $WAS_HOME |
清單1展示了如何配置 WAS_HOME。
在 Windows 平臺中使用 set 命令進(jìn)行設(shè)置,以后可以通過 %WAS_HOME% 進(jìn)行訪問。
在 Linux 平臺中使用 export 命令進(jìn)行設(shè)置,以后可以通過 $WAS_HOME 進(jìn)行訪問。如果要使環(huán)境變量 WAS_HOME 在系統(tǒng)啟動時自動設(shè)置,可以將 export 語句添加到 boot.local 文件中。
在正式的測試之前,WAS 上的 JAAS 錄模塊需要更新到最新的版本。為了保證最新版本的成功更新,我們首先要將舊版本的 JAAS 登錄模塊刪除(如果存在的話),如清單 2 所示。
清單 2. 刪除 JAAS 登錄模塊 – DeleteLoginModule.py
01 loginModuleAlias = "wssecurity.KerberosToken" 02 lineSeparator = java.lang.System.getProperty('line.separator') 03 cells = AdminConfig.list("Cell").split(lineSeparator) 04 for cell in cells : 05 security = AdminConfig.list("Security", cell) 06 appLoginConfig = AdminConfig.showAttribute(security, "applicationLoginConfig") 07 jaasConfigEntryString = AdminConfig.list("JAASConfigurationEntry", appLoginConfig) 08 jaasConfigEntry = jaasConfigEntryString.split(lineSeparator) 09 entry = None 10 for eachEntry in jaasConfigurationEntrys : 11 jlmAlias = AdminConfig.showAttribute(eachEntry, "alias") 12 if jlmAlias == loginModuleAlias : 13 entry = eachEntry 14 print "\nEntry found: " + entry 15 break 16 if entry != None : 17 AdminConfig.remove(entry) 18 print "\nEntry deleted: " + entry 19 AdminConfig.save() |
清單 2 展示了如何使用 wsadmin 腳本來刪除 WAS 上的 JAAS 登錄模塊。WAS 的 wsadmin腳本支持 Jacl 和 Jython 兩種類型的腳本語言,這個示例采用了 Jython 語言。
其中,第 1 行設(shè)置了 loginModuleAlias 變量,用于保存待刪除的 JAAS 登錄模塊的別名。第 2 行定義了 lineSeparator 常量,用于表示換行符。第 3-4 行獲取了 WAS 中的 Cell 列表,并遍歷整個 Cell 列表,對每個 Cell 進(jìn)行處理。第 5-6 行獲取了 Cell 中的安全配置,得到 Application Login Configuration。第 7-8 行進(jìn)一步獲取 Cell 中的 JAAS 登錄模塊的列表。
第 9 行設(shè)置了 entry 變量,用于保存查找到的待刪除的 JAAS 登錄模塊,初始值設(shè)為 None,表示未找到。
第 10-15 行是一個循環(huán),遍歷 Cell 中的 JAAS 登錄模塊的列表。對每個 JAAS 登錄模塊,第 11 行首先獲取它的別名,第 12 行將別名與 loginModuleAlias 變量中保存的待刪除的 JAAS 登錄模塊的別名進(jìn)行比較,如果相同則說明這個 JAAS 登錄模塊就是待刪除的登錄模塊。第 13 行將該 JAAS 登錄模塊保存在 entry 變量中,第 14 行打印出找到待刪除登錄模塊的日志信息,第 15 行則退出循環(huán)。如果在循環(huán)沒有找到和待刪除登錄模塊相匹配的,則 entry 變量保持為 None。
第 16-19 行是刪除登錄模塊的代碼,第 16 行判斷一下是否找到待刪除登錄模塊,如果 entry 變量為 None,則說明沒有找到,直接退出。反之,第 17 行執(zhí)行刪除,第 18 行打印出刪除日志信息,第 19 行保存更改。
在我們的示例中,刪除 JAAS 登錄模塊腳本是存放在一臺 Linux 系統(tǒng)中,我們要通過這個Linux 系統(tǒng)上的 WAS 來刪除環(huán)境中的其它系統(tǒng)上的 WAS 中的 JAAS 登錄模塊,這個操作需要通過 wsadmin 工具來遠(yuǎn)程訪問其它 WAS。調(diào)用過程如清單 3 所示。
清單 3. 調(diào)用刪除 JAAS 登錄模塊 – DeleteLoginModule.sh
01 $WAS_HOME/bin/wsadmin.sh 02 -conntype SOAP 03 -host 172.16.0.124 04 -username wasadmin -password passw0rd 05 -lang jython 06 -f DeleteLoginModule.py |
清單 3 展示了如何通過 wsadmin 工具調(diào)用刪除 JAAS 登錄模塊的方法。
第 1 行 $WAS_HOME/bin/wsadmin.sh 為 wsadmin 工具,用于管理 WAS 以及配置、應(yīng)用程序部署和服務(wù)器運(yùn)行時操作。
第 2 行指定使用的連接方式為 SOAP,連接方式可能的類型包含:SOAP、RMI 和 NONE。第3行指定目標(biāo) WAS 的主機(jī)名。第4行指定用來連接到遠(yuǎn)程 WAS 的用戶名和密碼。第5行指定腳本文件的語言采用 Jython 語言,可能的語言包括: Jacl 和 Jython 。第6行指定在目標(biāo) WAS 上要運(yùn)行的腳本。
(注:第 1 行到第 6 行為一條完整的命令,此處為講解方便分解成 6 行)
在更新(安裝或刪除) JAAS 登錄模塊之后,必須重新啟動 WAS,以使更新生效。每個WAS 機(jī)器上都需要準(zhǔn)備重啟的腳本,該腳本在本地運(yùn)行,控制指令通過 STAF/STAX 遠(yuǎn)程發(fā)起。 WAS重啟腳本,如清單 4 所示。
清單 4. 重啟WAS
[Windows Platform] %WAS_HOME%\bin\stopServer.bat server1 -user wasadmin -password passw0rd %WAS_HOME%\bin\startServer.bat server1 [Linux Platform] $WAS_HOME/bin/stopServer.sh server1 -user wasadmin -password passw0rd $WAS_HOME/bin/startServer.sh server1 |
清單4展示了如何重啟 WAS。其中,stopServer.sh 用于停止 WAS。如果啟用了全局安全,則需要設(shè)定連接 WAS 的用戶名和密碼。startServer.sh 用于啟動 WAS。
在每次測試之前,需要將 WAS 上部署的應(yīng)用程序更新到最新的版本。為了保證最新版本的成功更新,我們首先要將舊版本的應(yīng)用程序刪除(如果存在的話),然后按照新版本的應(yīng)用程序,最后啟動新安裝的應(yīng)用程序。完整的過程如清單 5 所示。
清單 5. 部署應(yīng)用程序 – UpdateApplication.py
01 import sys 02 # define uninstall application 03 def uninstallApp(appName): 04 try: 05 print '\nUninstall ' + appName + '...' 06 AdminApp.uninstall(appName) 07 AdminConfig.save() 08 except: 09 print sys.exc_type, sys.exc_value 10 print '[FAIL]' 11 else: 12 print '[OK]' 13 # define install application 14 def installApp(appName, earFileName): 15 try: 16 print '\nInstall ' + appName + ' (' + earFileName + ')...' 17 AdminApp.install(earFileName, ['-appname', appName]) 18 AdminConfig.save() 19 except: 20 print sys.exc_type, sys.exc_value 21 print '[FAIL]' 22 else: 23 print '[OK]' 24 # define start application 25 def startApp(appName): 26 try: 27 print '\nStart ' + appName + '...' 28 appMgr = AdminControl.queryNames('type=ApplicationManager,process=server1,*') 29 AdminControl.invoke(appMgr, 'startApplication', appName) 30 AdminConfig.save() 31 except: 32 print sys.exc_type, sys.exc_value 33 print '[FAIL]' 34 else: 35 print '[OK]' 36 # parse command line arguments 37 argLen = len(sys.argv) 38 appName = '' 39 if argLen > 0: 40 appName = sys.argv[0] 41 earFileName = appName + '.ear' 42 if argLen > 1: 43 earFileName = sys.argv[1] 44 # update application 45 uninstallApp(appName) 46 installApp(appName, earFileName) 47 startApp(appName) |
清單 5 展示了如何在 WAS 上重新部署應(yīng)用程序。
其中,第 1 行導(dǎo)入了系統(tǒng)函數(shù)庫 sys。
第 2-12 行定義了函數(shù) uninstallApp,用于卸載已安裝的應(yīng)用程序。第 3 行是函數(shù)的聲明,該函數(shù)包含一個參數(shù) appName,即待卸載的應(yīng)用程序名稱。第 4、8、11 行是一個 try…except…else… 的異常處理模塊,用于對卸載過程中發(fā)生的任何異常進(jìn)行處理,并將異常信息返回給用戶。第 6 行執(zhí)行卸載操作,第 7 行保存卸載操作的更改。如果在卸載過程中發(fā)生異常,第 9 行將異常的類型和異常的信息顯示給用戶,第 10 行告知用戶操作失敗。反之,第 12 行告知用戶操作成功。
第 13-23 行定義了函數(shù) installApp,用于安裝新的應(yīng)用程序。第 14 行是函數(shù)的聲明,該函數(shù)包含兩個參數(shù): appName 為待安裝的應(yīng)用程序名稱, earFileName 為待安裝的EAR包的文件名。第 17 行執(zhí)行安裝操作。其它代碼與函數(shù) uninstallApp 中的相應(yīng)代碼類似。
第 24-35 行定義了函數(shù) startApp,用于啟動應(yīng)用程序。第 25 行是函數(shù)的聲明,該函數(shù)包含一個參數(shù) appName ,即待啟動的應(yīng)用程序名稱。第 28 行獲取 Application Manager 對象,第 29 行執(zhí)行啟動操作。其它代碼與函數(shù) uninstallApp 中的相應(yīng)代碼類似。
第 36-43 行解析命令行參數(shù),第一個參數(shù)為應(yīng)用程序名稱,是必須的;第二個參數(shù)為應(yīng)用程序EAR 包的名稱,是可選的,如果省略,則在應(yīng)用程序名稱后加上 ’.ear’ 來代替。
第 44-47 行更新應(yīng)用程序,首先刪除現(xiàn)有的應(yīng)用程序,然后按照新的應(yīng)用程序,最后啟動新安裝的應(yīng)用程序。
在我們的示例中,部署應(yīng)用程序腳本是存放在一臺 Linux 系統(tǒng)中,這臺 Linux 系統(tǒng)稱為部署服務(wù)器。我們要通過部署服務(wù)器上的 WAS 來更新環(huán)境中的其它系統(tǒng)上的 WAS 中的應(yīng)用程序。這個調(diào)用過程是通過 wsadmin 工具來完成的,腳本和“調(diào)用刪除 JAAS 登錄模塊”腳本類似,請參見清單 3,此處不再贅述。
STAF/STAX 腳本包括以下部分:
- 環(huán)境清理
- 下載配置 WAS 登錄模塊腳本
- 分發(fā)和運(yùn)行配置 WAS 登錄腳本
- 重啟 WAS
- 復(fù)制源碼到編譯機(jī)
- 控制編譯機(jī)編譯源碼
- 復(fù)制 WAR 到部署機(jī)器上并部署
- 調(diào)用測試代碼
- 收集日志
下面我們分別介紹每個部分的腳本。
在進(jìn)行自動化編譯、部署和測試之前,需要對上次測試的環(huán)境進(jìn)行清理,以除去上次測試的殘留,保證測試結(jié)果的正確和合理。首先我們需要調(diào)用第 4 章的 WAS clean 腳本來刪除 WAS 中的登錄模塊。
清單 6. STAX 調(diào)用 WAS clean 腳本示例
1 <script> 2 machineList = [‘was602_Linux’, ‘was61_Linux’, ‘was602_Windows’, ‘was61_Windows’] 3 </script> 4 <paralleliterate var=”machine” in=”machineList”> 5 <if expr=“machine.find(‘Linux’)>=0 ”> 6 <sequence> 7 <stafcmd> 8 <location> ‘%s’ % machine </location> 9 <service> ‘process’ </service> 10 <request> ‘start command "/root/script/CleanupEnv.sh" username "root" password 11 "password" workdir "/root/script" wait stdout /root/script/cleanupEnv%s.log' 12 % machineName 13 </request> 14 </stafcmd> 15 </sequence> 16 </if> 17 <if expr=“machine.find(‘Windows)>=0 ”> 18 <sequence> 19 <stafcmd> 20 <location> ‘%s’ % machine </location> 21 <service> ‘process’ </service> 22 <request> ‘start command "C:/script/CleanupEnv.bat" username "Administrator" 23 password "password" workdir "C:/script" wait stdout 24 C:/script/cleanupEnv%s.log' % machineName 25 </request> 26 </stafcmd> 27 </sequence> 28 </if> 29 </paralleliterate> |
在清單 6 中,我們把系統(tǒng)分成了兩套環(huán)境,Windows 系統(tǒng)和 Linux 系統(tǒng),針對于不同的環(huán)境,cleanupEnv 腳本有不同的路徑和后綴名。首先 4-29 行使用了并行的遍歷來分別在各個系統(tǒng)上調(diào)用 cleanupEnv 腳本。在第 5 行和第 17 行中,if 語句使用的 expr 用 python 來解析,因此可以用 python 來寫一些復(fù)雜的比較和判斷語句。find 函數(shù)表示在字符串中查找指定的字符串。
5-16 行針對于 Linux 的系統(tǒng),使用 root 用戶來調(diào)用 CleanupEnv.sh 腳本。17-28 行針對于Windows 系統(tǒng),使用 Administrator 用戶來調(diào)用 CleanupEnv.bat 腳本。
CleanupEnv 腳本有兩種儲存方法:
- 事先存放在各個測試機(jī)器上
- 存放在 CruiseControl 控制機(jī)器上,然后由 STAX 來根據(jù)環(huán)境來分發(fā)這些腳本。
一般情況下,推薦使用第二種方法。腳本分布在不同的機(jī)器上,如果發(fā)生一點小的改動,極易引起腳本的不同步。使用第二種方法,不僅會避免這個問題,而且只需改動一個腳本,將極大的節(jié)省測試人員的工作量。使用第二種方法只需在第 7 行和第 19 行前面加上 STAF 復(fù)制文件的命令即可。在 Linux 上如下所示:
清單 7. STAX 分發(fā) CleanupEnv 腳本示例
<stafcmd> <location> ‘%s’ % machine </location> <service> ‘fs’ </service> <request> ‘copy FILE "D:/sample/CleanupEnv.sh" TODIRECTORY /root/script/’ </request> </stafcmd> |
把文件復(fù)制到 Linux 上需要注意一個問題,就是文件的某些屬性可能沒有被復(fù)制,比如可執(zhí)行屬性,因此需要使用下面的命令來更改文件的屬性,以便用戶能夠執(zhí)行此文件。
清單 8. STAX 更改文件屬性
<stafcmd> <location> ‘%s’ % machine </location> <service> ‘process’ </service> <request> ‘start command "chmod +x /root/script/CleanupEnv.sh"’ </request> </stafcmd> |
在刪除上次自動化測試配置的登錄模塊之后,我們需要從 FTP 下載最新版本的配置登錄模塊的腳本。本文使用 Windows 自帶的 FTP 命令來完成腳本的下載。FTP 上存放了不同時期的版本,每個版本使用文件名+時間戳的方式來區(qū)分,而 FTP 命令并沒有提供下載最新腳本的功能,因此我們需要自己來判斷那個腳本是最新的。首先利用 FTP 的 ls 命令來列出所有的版本文件,通過 java 程序來判斷哪個是最新的版本,最后再利用 FTP 命令來下載最新的版本。STAX 腳本如下所示:
清單 9. 下載最新的版本文件
<sequence> <process> <location>'local'</location> <command>'ftp'</command> <parms>'-s:C:/Sample/ftpconf/ftplist.conf'</parms> <workdir>'C:/Sample'</workdir> </process> <process> <location>'local'</location> <command>'java'</command> <parms>'-cp . fileParsing.ParseBuildTime temp.txt ftptemplate.conf ftpdown.conf'</parms> <workdir>'C:/Sample'</workdir> </process> <process> <location>'local'</location> <command>'ftp'</command> <parms>'-s:C:/Sample/ftpconf/ftpdown.conf'</parms> <workdir>'C:/Sample'</workdir> </process> </sequence> |
其中第一個 Process 命令從 FTP 服務(wù)器上獲取所有的版本文件信息,保存到 temp.txt 文件中。ParseBuildTime 用來從版本文件列表 temp.txt 中找出最新的版本文件,并且根據(jù)提供的 FTP 模板文件 ftptemplate.conf 生成 FTP 腳本 ftpdown.conf,供 STAX 腳本調(diào)用下載最新的版本文件。第三個 Process 命令調(diào)用 ftpdown.conf 從 FTP 服務(wù)器下載最新的版本文件。
清單 10 顯示了 FTP 模板文件,它是由一系列 FTP 命令組成。
清單 10. FTP 模板腳本
open ftp.ibm.com user password binary prompt cd /sampledirectory lcd C:\Sample\build get "<template>" ConfigureLoginModule.zip bye |
本節(jié)把下載的最新版本文件解壓縮后分發(fā)到 WAS 平臺。解壓縮使用 Winrar 命令來進(jìn)行,如下所示:
清單 11. 使用 Winrar 命令解壓縮
<process> <location>'local'</location> <command>'C:\Program Files\winrar\winrar.exe'</command> <parms>'x -o+ C:/Sample/build/ConfigureLoginModule.zip'</parms> <workdir>'D:/STAFDirectory/build/'</workdir> </process> |
如何分發(fā)文件和清單 7 類似,這里不再贅述。
將配置 WAS 登錄模塊腳本分發(fā)完成后,需要調(diào)用它完成 WAS 登錄模塊的配置。調(diào)用腳本的STAX 代碼與清單 6 類似,這里也不再贅述。
在完成 WAS 登錄模塊配置后,需要重啟 WAS 來使配置生效。這里調(diào)用第三章的 WAS 重啟腳本來完成WAS服務(wù)器的重啟。在調(diào)用 WAS 重啟腳本之前,需要分發(fā)此腳本到每個 WAS 服務(wù)器上。過程類似于清單 6 和清單 7 。有一點不同的是, WAS 重啟腳本可能會需要運(yùn)行較長一段時間,比如 5 分鐘,因此 STAX 命令中的 wait 關(guān)鍵字不能忽略,表示需要等待 WAS 重啟結(jié)束,如下所示:
清單 12. STAX 重啟 WAS 腳本示例
<stafcmd> <location> ‘%s’ % machine </location> <service> ‘process’ </service> <request> ‘start command "/root/script/RestartServer.sh" username "root" password "password" workdir "/root/script" wait stdout /root/script/RestartServer%s.log' % machineName </request> </stafcmd> |
在啟動測試過程之前,CruiseControl 會調(diào)用 Ant 腳本從 CVS 下載最新的源碼,包括 Web Service 源碼、測試代碼和 RFT 代碼。在測試之前,我們需要將它們復(fù)制到編譯機(jī)上進(jìn)行編譯,因為某些代碼需要依賴于 WAS 或者 RFT 平臺。
復(fù)制代碼分為三個部分:
- 復(fù)制 Web Service 源碼(被測試代碼)。
- 復(fù)制測試代碼 (Web Service 客戶端以及 JUnit 代碼)
- 復(fù)制 RFT 代碼。
復(fù)制過程和清單 7 類似。
每個部分的源碼都有 build.xml 文件,所以只需要調(diào)用 Ant 命令來編譯即可。
清單 13. 編譯源碼
<stafcmd> <location>'%s' % machine</location> <service>'process'</service> <request>'start command "c:/apache-ant-1.6.5/bin/ant.bat -buildfile %s/build.xml > %s/build.log" username "Administrator" password "password" workdir %s wait' % (sourceLocation, sourceLocation, sourceLocation) </request> </stafcmd> |
與編譯 Web Service 源碼和測試代碼不同的是, RFT 代碼需要指定 RFT 安裝的位置,這通過傳遞 Ant 參數(shù)來實現(xiàn),如清單 14 所示。
清單 14. 編譯 RFT 測試腳本
<stafcmd> <location>'%s' % machine </location> <service>'process'</service> <request>'start command "c:/apache-ant-1.6.5/bin/ant.bat -buildfile %s/buildRFT.xml -DRFTDriver=%s > %s/build.log" username "Administrator" password "password" workdir %s wait' % (sourceLocation, RFTDriver, sourceLocation, sourceLocation) </request> </stafcmd> |
編譯完成后,需要將編譯生成的 WAR 文件到部署機(jī)器上并且通過部署機(jī)器來遠(yuǎn)程部署所有的WAS 服務(wù)器。
清單 15.部署 WAR
<stafcmd> <location>'%s' % machine </location> <service>'process'</service> <request>'start command "/root/script/deploywar.sh" username "root" password "password" workdir "/root/script/work" wait stdout /root/script/deploy.log STDERRTOSTDOUT' </request> </stafcmd> |
我們選擇通過一臺部署機(jī)器來部署 WAR 的原因是這樣做維護(hù)比較簡單,如果 WAS 服務(wù)器IP 改變或者增加時,只需要更改部署服務(wù)器的部署腳本即可,甚至對 STAX 腳本也不用更改。當(dāng)然也可以選擇每臺 WAS 分別對自己部署 WAR,這樣當(dāng) WAS 服務(wù)器增加時,需要對 STAX 腳本做一點更改,添加相應(yīng)的 WAS 服務(wù)器。
部署完成后,在編譯機(jī)器上調(diào)用測試代碼(包括 RFT 代碼)來測試示例 Web Service 程序。
調(diào)用代碼有兩種方式:
- STAX 直接調(diào)用遠(yuǎn)程機(jī)器上的 Java 命令來執(zhí)行
- STAX 調(diào)用遠(yuǎn)程機(jī)器上的 Ant 腳本來執(zhí)行
為了演示這兩種方式的用法,我們使用 Ant 腳本來調(diào)用 JUnit 測試代碼,使用 Java 命令來調(diào)用 RFT 代碼。但在實際使用過程中,我們推薦使用 Ant 腳本來調(diào)用。
清單 16. 調(diào)用測試代碼
<stafcmd> <location>'%s' % machine </location> <service>'process'</service> <request>'start command "c:/apache-ant-1.6.5/bin/ant.bat -buildfile %s/runTest.xml > %s/runTest.log" username "Administrator" password "password" workdir %s wait' % (sourceLocation, sourceLocation, sourceLocation) </request> </stafcmd> <stafcmd> <location>'%s' % machine </location> <service>'process'</service> <request>'start command "java -cp "%s\bin\rational_ft.jar" -Drational_ft.install.dir ="%s\bin" com.rational.test.ft.rational_ft -datastore "%s" -rt.log_format "html" -rt.bring_up_logviewer false -playback testscript.VerifyWebService >%s/runRFTTest.log" username "Administrator" password "password" workdir %s wait' % (RFTLocation, RFTLocation, sourceLocation, sourceLocation, sourceLocation) </request> </stafcmd> |
第一個 STAFCMD 使用 Ant 來調(diào)用 Junit 測試代碼,可以看出命令比較簡單。而第二個STAFCMD 使用 Java 來調(diào)用 RFT 測試腳本,命令要復(fù)雜得多,這樣會給維護(hù)帶來一定的困難,因此推薦使用 Ant 來編譯和調(diào)用。
在部署和測試完成后,控制機(jī)器需要遍歷每個 WAS 服務(wù)器(包括編譯機(jī)和部署機(jī))來收集日志文件,也就是復(fù)制文件到控制機(jī)器上。這與清單 7 類似。
至此,我們已經(jīng)完成了這個 STAX 腳本的編寫。需要指出的是,所有的 STAX 腳本只需要在控制機(jī)器上執(zhí)行即可,部署機(jī)、編譯機(jī)以及測試機(jī)器完成不知道這些代碼的存在,它們只需要安裝 STAF 并且信任控制機(jī)器即可。
CruiseControl 是一個非常容易使用的持續(xù)集成工具。讀者可以從它的官方網(wǎng)站下載最新版的CruiseControl 2.7 安裝包進(jìn)行安裝。由于安裝十分簡單,本文略過其安裝過程。
在 Dos 命令行窗口中運(yùn)行如下命令來驗證你可以從 CVS 檢出源代碼 (假定我們使用 cygwin來連接 CVS )
cd <build_home> set CVS_RSH=c:\cygwin\bin\ssh.exe \progra~1\cvs\cvs -d :ext:user@cvshostname:/cvsroot/sampleproject/ checkout -d <build_home> Build |
配置完成 CVS 后,在 build.xml 中添加如下任務(wù):
清單17. 檢出 CVS 上測試源代碼的 ant 腳本
<target name="getSrc"> <echo message="Extracing source from CVS in to ${build.src.dir}" /> <cvs cvsRoot=":ext:user@cvshostname:/cvsroot/sampleproject/" command="checkout -P" cvsRsh="c:\cygwin\bin\ssh.exe" package="src/test" dest="${cvs.dir}"/> <copy todir="${src.dir}"> <fileset dir="${cvs.dir}/src/test> <exclude name="**/CVS/**"/> </fileset> </copy> </target> |
注意:用戶也可以直接通過配置使用 CruiseControl 來檢出和編譯源代碼。但是由于在本文的場景中,編譯這些測試代碼需要有特定的類庫支持,而 CruiseControl 所處的控制機(jī)沒有安裝這些類庫。因此在本文中我們使用一個 ant 腳本來將代碼從 CVS 檢出并在后面的步驟中將其發(fā)布到編譯機(jī)上進(jìn)行編譯。
為了讓測試腳本能夠每天定時運(yùn)行,需要在 CruiseControl 中配置定時器。在 CruiseControl 的安裝目錄中找到 “config.xml” 并添加下面的配置代碼:
清單 18. 在 CruiseControl 中配置定時器
<schedule interval="300"> <composite time="0030"> <ant anthome="C:\Program Files\CruiseControl\apache-ant-1.6.5" target="buildAll" buildfile="d:\ build\build.xml"/> <exec command="d:\STAFDirectory\script\execute.bat" /> </composite> </schedule> |
上述的設(shè)置設(shè)定了 1 個定時器,在凌晨 3 點執(zhí)行。定時器先運(yùn)行一個 Ant 腳本將代碼檢出復(fù)制到一個本地文件夾中,再運(yùn)行一個批處理命令 “execute.bat” 來啟動后續(xù)的 STAF 命令。
當(dāng)測試腳本源代碼被檢出到一個本地文件夾后,批處理命令 “execute.bat” 被執(zhí)行。這個批處理命令只有一行代碼,就是執(zhí)行一個 STAX 任務(wù):
staf local stax execute file D:\\STAFDirectory\\script\\main.xml wait |
這個 STAX 任務(wù)已經(jīng)在前面的章節(jié)中做了詳細(xì)的介紹,此處不再重復(fù)。
在本場景中,當(dāng)測試運(yùn)行完成后測試的結(jié)果和日志需要被發(fā)布到 CruiseControl 的 Web 控制臺中。但是由于測試執(zhí)行是在另一臺服務(wù)器上完成的,因此 CruiseControl 所在的控制機(jī)不能直接訪問這些日志。我們只有創(chuàng)建另一個 STAX 任務(wù)把測試日志從執(zhí)行測試的編譯機(jī)上復(fù)制到控制機(jī)上。
CruiseControl 內(nèi)建了對 JUnit 產(chǎn)生的 XML 格式的日志的支持。為了讓 CruiseControl 能夠正確的顯示測試日志,需要在其配置文件 “config.xml” 中添加如下設(shè)置:
清單19. 在 CruiseControl 中合并 JUnit 測試日志
<log> <merge dir="projects/${project.name}/target/test-results" /> </log> |
發(fā)布 RFT 日志和編譯的運(yùn)行時代碼到 CruiseControl 控制臺
RFT 運(yùn)行的日志文件有兩種類型,純文本日志和 HTML 格式的日志。CruiseControl 目前還不支持直接顯示 RFT 日志文件。因此我們只能把 RFT 產(chǎn)出的 HTML 日志文件作為一種編譯產(chǎn)出放置在特定文件夾下。這樣用戶可以通過 CruiseControl 控制臺直接訪問該 HTML。
在編譯機(jī)上編譯得到的 WebService 和客戶端的 war 文件作為一個編譯產(chǎn)出也被存檔保留,并通過 CruiseControl 發(fā)布。當(dāng)測試發(fā)現(xiàn)缺陷后,測試員可以通過這些 war 文件來追溯到某一特定版本的編譯產(chǎn)出并重現(xiàn)缺陷,開發(fā)人員則可以在這一基礎(chǔ)上進(jìn)行調(diào)試和修正。
添加如下代碼到 CruiseControl 配置文件 “config.xml” 中:
清單20. 在 CruiseControl 中發(fā)布 RFT 測試日志
<publishers> <onsuccess> <artifactspublisher dest="artifacts/${project.name}" dir="projects/${project.name}/target/buildArtifacts" /> </onsuccess> </publishers> |
本章介紹用于測試 Web Service 的 JUnit Test Case 示例,這個例子將詳細(xì)說明如何利用HttpUnit 來測試 Web Service。在這個例子中,共有三方參與,分別為 Web Service Provider、Web Service Client 和 Test Client。首先由 Test Client 向 Web Service Client 發(fā)出 HTTP 測試請求,Web Service Client 在驗證用戶身份后,生成相應(yīng)的 SOAP 請求發(fā)給 Web Service Provider,
Web Service Provider 同樣在驗證用戶身份后為其提供 Web Service 服務(wù),并將結(jié)果仍以 SOAP的形式返回到 Web Service Client,再由 Web Service Client 以 HTTP 形式返回結(jié)果給 Test Client。最后由 Test Client 對返回結(jié)果的正確性進(jìn)行判斷并給出測試結(jié)果。JUnit Test Case 示例如清單 21 所示。
清單 21. JUnit Test Case 示例
01 public class SampleTest extends TestCase {
02 private String invoke_client(
03 String requestString, String clientURL, String providerURL) {
04 String result = null;
05 String requestURL = clientURL + "?endpoint=" + providerURL
06 + "&requestString=" + requestString;
07 WebConversation wc = new WebConversation();
08 wc.setAuthorization(SampleConst.Username, SampleConst.Password);
09 WebRequest req = new GetMethodWebRequest(requestURL);
10 WebResponse resp;
11 String responseString;
12 try {
13 resp = wc.getResponse(req);
14 responseString = resp.getText();
15 } catch (AuthorizationRequiredException e) {
16 result = "Invalid UserID or Password.";
17 return result;
18 } catch (Exception e) {
19 result = "Exception on HTTP request";
20 return result;
21 }
22 int checkNames = responseString.indexOf("User names strings match");
23 int checkRequest = responseString.indexOf("Request strings match");
24 if ((checkStrings == -1) | (checkNames == -1) | (checkRequest == -1)) {
25 result = "Strings not match";
26 }
27 return result;
28 }
29 public void test_sample_case_1() {
30 String requestString = "sample_case_1";
31 String result = invoke_client(requestString,
32 SampleConst.ClientWebURL,SampleConst.ProviderWebURL);
33 assertTrue(result, result == null);
34 }
35 }
清單 21 展示了訪問 Web Service 的 JUnit Test Case 示例。
其中,第 2-29 行定義了 invoke_client 函數(shù),通過 WebConversation 對 Web Service 進(jìn)行訪問。第 5-6 行設(shè)置了 Web Service Client 的地址,endpoint 為 Web Service Provider 的地址。第 8 行為訪問 Web Service 添加了身份認(rèn)證信息。第 12-21 行訪問 Web Service,將結(jié)果存入 responseString。如果在訪問過程中發(fā)生異常,則直接返回錯誤信息。第 22-28 行對返回結(jié)果進(jìn)行驗證,如果發(fā)現(xiàn)結(jié)果錯誤,則返回錯誤信息。否則返回 null 表示訪問成功。
第 30-35 行為一個 Test 的例子,通過調(diào)用 invoke_client 對 Web Service 進(jìn)行測試,并驗證返回的錯誤消息是否為 null。如果為 null 表示測試成功,反之則失敗。
本文使用 CruiseControl、STAF(STAX)、JUnit、Rational Functional Tester 通過一個簡化的具體場景展示了自動化測試平臺的實現(xiàn)。這個平臺不僅可以大大簡化測試人員的工作量,減輕測試人員的工作負(fù)擔(dān),也能保證開發(fā)版本的穩(wěn)定性,使開發(fā)人員盡早知道新版本的問題,增強(qiáng)開發(fā)人員的信心。
本文僅代表作者本人觀點,不代表 IBM 公司觀點。
- 學(xué)習(xí)多媒體課堂:如何實現(xiàn)軟件產(chǎn)品的自動化構(gòu)建和發(fā)布,本講座介紹如何實現(xiàn)軟件產(chǎn)品的自動化構(gòu)建和發(fā)布方面的主題,以及如何運(yùn)用 IBM Rational Build Forge 來實現(xiàn)自動化構(gòu)建與發(fā)布。
- 學(xué)習(xí)教程:利用 IBM Rational Build Forge 完善構(gòu)建過程,第 1 部分: 創(chuàng)建一個持續(xù)構(gòu)建和集成環(huán)境。這個教程循序漸進(jìn)地向您展示了如何安裝和配置 IBM Rational Build Forge,來管理從源代碼開始對 Jakarta Tomcat 的構(gòu)建。
- 通過 用 IBM Rational Build Forge 打造集成的軟件構(gòu)建管理平臺,第 1 部分: 構(gòu)建管理入門 了解如何通過整合項目組、流程以及系統(tǒng)來改進(jìn)軟件開發(fā)效率,從而提高整個開發(fā)團(tuán)隊的效率,改進(jìn)產(chǎn)品質(zhì)量,更好地遵規(guī)。
- 查看文章 “讓開發(fā)自動化: 使用自動化加速部署"了解如何結(jié)合使用 Ant 和 Java Secure Channel 將軟件遠(yuǎn)程部署到多個目標(biāo)環(huán)境中。
- 查看文章 “利用 STAF 實現(xiàn)程序更新包的自動部署測試”,了解 STAF(STAX) 基礎(chǔ)知識。
- 瀏覽“STAF 網(wǎng)站”,了解更多 STAF(STAX) 內(nèi)容以及下載 STAF(STAX)。
- 瀏覽“CruiseControl 網(wǎng)站”,了解更多 CruiseControl 內(nèi)容。
- 瀏覽“CruiseControl 配置頁面”,了解如何配置 CruiseControl。
- 使用 STAF 郵件列表,討論 STAF(STAX) 問題及用法。