應用 Rational 工具簡(jiǎn)化基于 J2EE 的項目第 8 部分 :測試軟件 本文是演示了在分布式的、基于 J2EE 的項目中使用 Rational 工具的系列文章(如下面所列)的第 8 部分。
第 1 部分: 項目介紹;高層次計劃
第 2 部分: 風(fēng)險管理;需求管理
第 3 部分: 模型創(chuàng )建和訪(fǎng)問(wèn)控制;需求分析
第 4 部分: 用例細化;產(chǎn)成報告;工具和技術(shù)選擇
第 5 部分: 體系架構和設計
第 6 部分: 詳細設計;早期開(kāi)發(fā);雙向工程;早期單元測試
第 7 部分: 繼續開(kāi)發(fā);早期的構建;演示
第 8 部分: 單元測試策略;功能測試;GUI 測試腳本 第 9 部分: 系統構建和測試;缺陷跟蹤;產(chǎn)品交付 第 10 部分: 項目完成;結論;未來(lái)的工作
本文中所虛構我們是一家軟件公司 Lookoff Technologies Incorporated,我們的客戶(hù) Audiophile Speaker Design, Inc. (ASDI),它雇用我們實(shí)現他們最初的 IT 需求。對于更詳細的信息,參見(jiàn)
第 1 部分。
本文是這個(gè)系列文章的第 8 部分,本文中對最初在這個(gè)系列的
第 6 部分介紹的測試方面的主題進(jìn)行了詳細的討論。在第 6 部分的文章中,我們看到了在早期的開(kāi)發(fā)當中我們開(kāi)始使用 Rational Purify 和 Rational Quantify 檢查內存的使用情況和性能的瓶頸。同時(shí)也討論了我們在早期的單元測試工作的很多細節。本文將描述這些工作的進(jìn)展,并回顧我們使用 Rational 測試工具的自動(dòng)化測試的能力來(lái)減少測試的成本,主要是 Rational PureCoverage 和 Rational Robot 的使用情況。在項目的這個(gè)階段,我們主要關(guān)注在功能測試(包括 GUI 測試)上,雖然我們也從事了一些早期的負載測試。
注意,這里使用的 Rational 統一過(guò)程(RUP)術(shù)語(yǔ)反映了測試的兩個(gè)不同的維度:“單元測試”是在將要被測試的軟件的開(kāi)發(fā)階段進(jìn)行的 — 在這個(gè)時(shí)候測試是針對最小的可測試的軟件單元的 — 而“功能測試”和“負載測試”是針對特定測試目標的,不管是在被測試軟件的哪個(gè)開(kāi)發(fā)階段。本文中所討論的關(guān)于單元測試的大多數內容也可以應用在我們后面的開(kāi)發(fā)階段的測試工作中(例如,在集成測試期間合并不同的組件或者子系統)。
第 8 部分快照
在第 8 部分演示的工具和技術(shù):
Rational PureCoverage — 用于在單元測試期間分析代碼的覆蓋率(代碼被執行的次數) Rational Robot — 為可重復的自動(dòng)化執行錄制和回放測試腳本 Rational Administrator — 用于創(chuàng )建項目,與 Rational Robot 一起使用,關(guān)聯(lián)與項目相關(guān)的測試腳本 Rational TestManager — 組織和管理測試,并查看測試的結果
被創(chuàng )建或者更新的產(chǎn)物:
Robot 測試腳本 — 為自動(dòng)化測試的執行而被創(chuàng )建
在開(kāi)發(fā)的進(jìn)展過(guò)程中,我們發(fā)現我們的單元測試工作超過(guò)了我們的開(kāi)發(fā)工作,因為我們正在構建的應用具有非常復雜的用戶(hù)交互。單元測試總是要求大量的工作,并且我們也許沒(méi)有足夠的預算和時(shí)間來(lái)執行大量的單元測試工作。我們發(fā)現我們的 GUI 測試,包括單調的手工測試的過(guò)程,尤其減慢了我們的速度。
雖然 ASDI 項目的第 1 階段只是一個(gè)概念上的驗證,但是我們也具有艱苦的時(shí)間忍耐在系統中顯而易見(jiàn)的 bug 。在擁有堅固、可靠的軟件和頻繁的集成、快速的演示之間找到一個(gè)平衡是非常不容易的。我們定義了第 1 階段項目的范圍,這樣我們就必須進(jìn)行不止一次的技術(shù)上的演示;客戶(hù)期望演示是一個(gè)可以使用的系統的 beta 版本。
這里,我們將看一下我們的單元測試工作的范圍,我們可以選擇(或者不)使用自動(dòng)化的能力,并且我們使用 Rational PureCoverage 來(lái)確定我們測試的徹底性。
單元測試的范圍 — 什么、多少次和什么時(shí)候測試 — 是幾個(gè)可變量的基礎,包括:
軟件的復雜程度 產(chǎn)品的特性和接口 被測試部分對整個(gè)產(chǎn)品是否是非常關(guān)鍵的 團隊對軟件中缺陷的容忍程度
在代碼測試的次數方面,在之前的項目中我們沒(méi)有打算在我們的軟件中進(jìn)行 100% 代碼覆蓋率的測試。完全的覆蓋是非常昂貴的并且很難達到,因為我們必須要手工的檢查我們的代碼以確定哪一行代碼沒(méi)有被測試覆蓋到。對單元測試的小的變化將要求我們重新檢查代碼以確保完全的覆蓋率被維護。然而,我們得感謝 Rational PureCoverage ,在 ASDI 項目中我們能夠容易得實(shí)現了接近 100% 的代碼覆蓋率(由于項目預算和范圍的原因,少量的未測試的殘留是被允許的)。PureCoverage 很大程度的簡(jiǎn)化了檢查代碼覆蓋率的任務(wù),這使識別哪一部分的代碼已經(jīng)或者還沒(méi)有被測試變得非常簡(jiǎn)單。
就像我們在這個(gè)系列的
第 6 部分提到的那樣,我們的單元測試工作幾乎與核心的軟件開(kāi)發(fā)本身開(kāi)始的一樣早。我們多數的開(kāi)發(fā)人員在他們擁有一個(gè)能夠被測試的軟件單元不久就開(kāi)始編寫(xiě)單元測試。他們喜歡當代碼在他們的頭腦中產(chǎn)生時(shí)測試軟件的內部構件。
單元測試的執行總是先于系統的構建;將明顯能夠通過(guò)單元測試來(lái)消除的簡(jiǎn)單缺陷引入到一個(gè)構建版本中是讓人不可接受的。單元測試總是在代碼被分發(fā)檢查之前被執行。此外,開(kāi)發(fā)人員以規范的基礎運行他們的單元測試以確保他們的定期變化不會(huì )破壞軟件。我們的方法不像一些軟件方法那樣激進(jìn) — 比如
極限編程(XP),在 XP 中單元測試的開(kāi)發(fā)通常是先于代碼的開(kāi)發(fā)的 — 但是我們將單元測試當作是一個(gè)重要的軟件開(kāi)發(fā)的早期步驟。
這里當然也有一些如何進(jìn)行測試的問(wèn)題,特別是什么樣的測試應該被自動(dòng)化的范圍。編寫(xiě)“后臺”(非 GUI )代碼的開(kāi)發(fā)人員是幸運的,他們能夠編寫(xiě)自動(dòng)化的測試,包括 Java 驅動(dòng)程序、代碼存根和腳本。然而,就像我們早些時(shí)候提到的,GUI 開(kāi)發(fā)人員的測試是更加困難的。
對于我們的非 GUI 測試,我們觀(guān)察了與每一個(gè)類(lèi)相關(guān)聯(lián)的單元測試的習慣;我們編寫(xiě)驅動(dòng)代碼訪(fǎng)問(wèn)類(lèi),并報告成功或者是失敗。我們嘗試使用能夠為我們自動(dòng)生成、管理和運行測試的測試框架,比如被 XP 所推薦的那些工具,但是他們將產(chǎn)生混雜的結果。雖然理論是很好的,但是這些框架(包括,比如
JUnit)對于我們的項目目的來(lái)說(shuō)來(lái)是不夠成熟的。不過(guò),我們的開(kāi)發(fā)人員非常自信如果他們有時(shí)間熟悉和對這些工具進(jìn)行改進(jìn),這些測試框架對我們的單元測試是非常有價(jià)值的。我們也許在將來(lái)的項目中更多的使用這些測試框架。在我們的 ASDI 項目中,采用 XP 的方法也許是太冒險了;相反,我們更加愿意接受 XP 在控制和風(fēng)險降低方法方面的概念和思想。你能夠在
the XProgramming.com 網(wǎng)站上找到大量有關(guān) XP 思想的內容。
我們沒(méi)有使用 Rational 的測試工具來(lái)測試非 GUI 的代碼,因為我們覺(jué)得他們不能達到一個(gè)足夠底層的級別。對于自動(dòng)化測試我們的 GUI 驅動(dòng)的代碼,Rational 的測試工具真的表現的非常出色。用戶(hù)界面測試是非常手工和交互的,并且要求大量的內容確認; Rational 的測試工具以一種一致的并快速的方式使我們反復的進(jìn)行這些測試變得更加的簡(jiǎn)單容易。
通過(guò)使用 Rational PureCoverage ,在我們的單元測試執行期間,我們能夠大幅的降低我們花在確定代碼覆蓋率上的時(shí)間 — 也就是說(shuō),哪些方法或者代碼行被執行或者被遺漏 。這個(gè)工具能夠使我們觀(guān)測我們提供的代碼覆蓋測試,然后決定是改進(jìn)測試還是通過(guò)手工檢查的方法來(lái)測試代碼。
PureCoverage 除了可以支持 C 或者 C++ 的應用程序以外,還可以支持 Java 程序,并且可以通過(guò)與 Quantify 相同的方式來(lái)配置和運行(在這個(gè)系列的
第 6 部分被討論過(guò))。這個(gè)工具能夠使我們?yōu)g覽我們的單元測試;以?xún)煞N方法進(jìn)行代碼覆蓋測試:使用 Coverage Browser 或者指定文件的 Coverage Fileview 方式。
使用 Coverage Browser 的方式(圖 1 ),我們能夠看到在單元測試中被包括的每一個(gè)文件(和目錄)的代碼覆蓋測試的統計學(xué)的總結。這些統計表包括了所有方法的調用次數,方法被訪(fǎng)問(wèn)或者遺漏的次數,還包括被訪(fǎng)問(wèn)或者遺漏的代碼行的數量。
圖 1: Coverage Browser
(
點(diǎn)擊放大)
我們能夠雙擊一個(gè)在總結中的方法來(lái)進(jìn)入 Coverage Fileview ,僅僅顯示在那個(gè)方法中哪些代碼行被訪(fǎng)問(wèn)或者被遺漏。就像被顯示在圖 2 中的例子,被遺漏的代碼行被用紅色突出出來(lái)(被訪(fǎng)問(wèn)的代碼行用藍色標識)。
圖 2: Coverage Fileview
(
click here to enlarge)
功能測試根據被定義在用例中的需求來(lái)驗證軟件是否正確的工作。為了確保我們測試了所有的需求,我們在設計和組織我們的功能測試時(shí)使用 Rational Robot 和 Rational TestManager 。(一個(gè)關(guān)于使用 Robot 的功能測試策略的討論能夠在 Robot 的用戶(hù)指南中被找到。)Robot 能夠使測試腳本更加容易的被錄制,然后為自動(dòng)化測試回放。使用 Robot 能夠創(chuàng )建兩種類(lèi)型的測試腳本:
GUI 腳本 記錄你的用戶(hù)界面動(dòng)作,當進(jìn)行回放時(shí),就像一個(gè)用戶(hù)在操作應用的登陸和控制程序的窗口。一些客戶(hù)端的測試 — 比如,嵌入到我們的 Web 應用中的 ActiveX 控件 — 需要使用這些腳本。因為 GUI 測試為我們造成了特殊的問(wèn)題,因此這類(lèi)的功能測試將在下一部分被詳細的討論。 VU scripts 當你使用它在包的級別上跟蹤什么樣的網(wǎng)絡(luò )信息被發(fā)送和接受時(shí),檢測你的應用。當進(jìn)行回放時(shí),這些腳本不必登陸應用就可以重新運行測試,這使他們比 GUI 腳本執行的更快。我們?yōu)槲覀兊?command gateway 的非 GUI 功能測試和 B2B 的負載測試使用 VU 腳本。
我們盡可能早的開(kāi)始創(chuàng )建我們的功能測試集合,因為這些測試對工程團隊來(lái)說(shuō)是非常有價(jià)值的工具。我們在代碼被分發(fā)檢查之前適當的擁有測試腳本的目標有時(shí)是很難實(shí)現的,可能是因為代碼的一些部分和一些組件要比其他的代碼和組件花費更多的時(shí)間來(lái)完成,或者是因為集成和測試(I&T)團隊太慢以至不能及時(shí)的完成測試腳本。在一種情況下,當用戶(hù)界面仍然在變化時(shí),測試腳本已經(jīng)被完成了;雖然一些返工是必要的,但是變化的出現是相當容易集成的。
一旦我們擁有了一個(gè)強有力的功能測試集合,重新測試系統將是非常容易的。這樣當你需要在后來(lái)的迭代中重新測試系統小的改變時(shí)得到很大的回報,并且可以確保變化不會(huì )影響其他的代碼部分。我們映射我們的功能測試腳本到用例上,以便我們可以立即知道當被關(guān)聯(lián)到被給定的用例的需求被修改時(shí)哪一個(gè)測試應該被運行。
當非 GUI 代碼的開(kāi)發(fā)人員非常高效的進(jìn)行他們的單元測試工作時(shí),JSP/servlet 的開(kāi)發(fā)人員將很難的保證時(shí)間的進(jìn)度。刺痛他們的是測試 GUI 域的過(guò)程,這個(gè)過(guò)程包括反復的執行下面的步驟:
在數據庫中建立測試數據。 通過(guò) Web 瀏覽器登陸應用。 導航被測試的頁(yè)面(一個(gè)表單要被填充)。 在頁(yè)面上填寫(xiě)一個(gè)或者多個(gè)域,依賴(lài)具體的測試。 點(diǎn)擊適當的按鈕提交表單。 檢查結果。 使用不同的測試(不同的域值或者不同的域)返回到步驟 4 ,直到所有合理的組合都被測試。
一些 GUI 測試尤其令人討厭,包括相同的入口,在幾個(gè)域中填寫(xiě)冗長(cháng)的值??梢允褂眉羟泻驼迟N,但是對于團隊來(lái)說(shuō)一遍一遍的重復這些測試仍然是非?,嵥榈墓ぷ?。有些頁(yè)面有 50 個(gè)不同的測試必須被執行,每個(gè)測試都包括很多的步驟。
雖然我們最初不傾向使用 Rational 的測試工具,但是我們覺(jué)得我們在 GUI 上的困難是我們深入研究 Rational 測試工具的很好的理由。我們決定使用 Rational Robot 來(lái)自動(dòng)化我們 GUI 的大部分測試。我們通過(guò)以下的方式調整了這些測試:
開(kāi)發(fā)人員為每一個(gè)測試起草一個(gè)單元測試說(shuō)明。 初級的集成與測試團隊成員接受單元測試說(shuō)明并基于當前的軟件構建版本創(chuàng )建測試腳本。 單元測試腳本是可配置管理的,以便對測試腳本的變更可以被跟蹤。 定期的,一個(gè)開(kāi)發(fā)人員給集成與測試團隊執行單元測試腳本的任務(wù),并提供一個(gè)根據單元測試說(shuō)明指明成功或者失敗的報告。
這個(gè)方法工作的非常好。它不僅僅在集成與測試團隊沒(méi)有太多的事情做的開(kāi)發(fā)過(guò)程的早期階段給他們在更多的工作,而且也給他們一個(gè)機會(huì )通過(guò)揭示單元測試說(shuō)明來(lái)了解整個(gè)軟件系統。此外,我們?yōu)?GUI 測試使用 Robot 的經(jīng)驗也為阿我們對其他的功能測試腳本進(jìn)行了準備。
當 Rational Robot 啟動(dòng)時(shí),它需要一個(gè)已存在項目(使用 Rational Administrator 創(chuàng )建的)的選擇,測試腳本將與這個(gè)項目進(jìn)行關(guān)聯(lián)。在我們的例子中,項目的定位必須是在網(wǎng)絡(luò )上可訪(fǎng)問(wèn)的,以便我們能夠在整個(gè)團隊中共享項目的數據庫。我們在 Administrator 中創(chuàng )建了 ASDI 項目,如圖 3 所示,并且當 Robot 提示我們選擇一個(gè)項目時(shí),我們選擇了這個(gè)項目。
圖 3: 使用 Rational Administrator 創(chuàng )建一個(gè)項目
作為一個(gè) GUI 測試的非常簡(jiǎn)單的例子,我們需要確證對于我們的 partSearch.jsp 頁(yè)面來(lái)說(shuō)客戶(hù)端的驗證是行為正確的,這個(gè)頁(yè)面執行了 JavaScript 的代碼來(lái)驗證他們域。每個(gè) ASDI 的條件,部分數字被輸入到整個(gè)頁(yè)面中,比如,必須是比 0 要大的整型數字;如果一個(gè)用戶(hù)輸入一個(gè)無(wú)效的數字,JavaScript 代碼就會(huì )報告一個(gè)錯誤,并且不會(huì )送壞的數據到服務(wù)器。我們的 JavaScript 代碼遵循了在
對于表單驗證的樣例代碼,我們在 FormChek.js 文件中編寫(xiě)了我們自己的驗證代碼。適當的使用這個(gè)代碼,一個(gè)負數的輸入會(huì )彈出如圖 4 所示的窗口。
圖 4: 適當的 partSearch.jsp 頁(yè)面驗證
我們在 Robot 中創(chuàng )建了一個(gè)測試腳本來(lái)測試數字域的驗證是否示適當的。首先 Robot 提示我們?yōu)槟_本提供一個(gè)名字(圖 5)。
圖 5: 錄制一個(gè)新的 GUI 腳本
在點(diǎn)擊 OK 這后,我們被提供了一個(gè)錄制控制器(圖 6),然后當 Robot 錄制我們的動(dòng)作時(shí),我們使用我們的基于窗口的應用。在這個(gè)例子中,我們啟動(dòng)了 Internet Explorer 5 ,在 partSearch.jsp 頁(yè)面進(jìn)行瀏覽,輸入一個(gè)壞的數字 (-123456),點(diǎn)擊 頁(yè)面上的 Submit 按鈕。
圖 6: Robot 錄制控制器
Robot 將我們的動(dòng)作記錄在一個(gè) GUI 腳本中(圖 7 )。這是一個(gè)非常簡(jiǎn)單的例子;我們實(shí)際的測試會(huì )包括更加復雜的測試腳本。我們不用創(chuàng )建成百上千個(gè)獨立的腳本,而是盡量為每一個(gè)屏幕界面設計一個(gè)大的腳本。在 Robot 的文章中有進(jìn)行測試設計的非常詳細的信息,我們能夠從 Robot 文檔中所推薦的內容中得到大量的借鑒。
圖 7: 簡(jiǎn)單的 Robot GUI 腳本
(
點(diǎn)擊放大)
通過(guò)使用易讀的并且可以容易的進(jìn)行編輯的腳本,我們就不必為只是有很小差異的測試重復的錄制測試腳本了。有時(shí)我們可以不用重新運行測試就直接編輯測試腳本,或者我們只是重新錄制一個(gè)測試的一小部分,然后將它粘貼到已存在的腳本中。
為了再一次運行測試,我們簡(jiǎn)單的在 Robot 的錄制控制器上(或者選擇 File 菜單上的 Playback )點(diǎn)擊 “play” 按鈕。腳本就像我們最初執行測試一樣回放我們的測試操作,并且當腳本運行完成時(shí),Rational TestManager 被啟動(dòng)來(lái)總結我們的測試結果。對于上面那個(gè)簡(jiǎn)單的例子,TestManager 在圖 8 中顯示的結果表明,測試腳本運行的結果是測試被通過(guò)。
圖 8: TestManager 報告 Robot 的測試通過(guò)
(
點(diǎn)擊放大)
假設我們想測試代碼的錯誤處理能力,比如壞的數字不再被捕獲 — 也就是說(shuō),沒(méi)有出現一個(gè)指明錯誤的窗口,我們的應用就會(huì )將整個(gè)數據傳送到 servlet 來(lái)執行查詢(xún)。當我們通過(guò)回放腳本重新運行這個(gè) GUI 測試時(shí),Robot 將會(huì )捕獲這個(gè)問(wèn)題,并且將結果寫(xiě)到報告中(圖 9 ),包括顯示出這個(gè)測試是失敗的。
圖 9: TestManager 報告 Robot 測試的失敗
(
點(diǎn)擊放大)
當我們開(kāi)始 ASDI 項目時(shí),我們期望使用 Rational 的分析和設計工具而不是 Rational 的測試工具。到項目第一階段的這個(gè)時(shí)期,我們非常驚訝并且也很高興的看到我們通過(guò)使用 Rational 的測試工具自動(dòng)化并且改進(jìn)了我們的測試過(guò)程。這些工具都有一個(gè)堅實(shí)的學(xué)習曲線(xiàn),但是一旦我們掌握我們每個(gè)工具的使用方法,我們的集成與測試團隊的生產(chǎn)力將大大的提高。在一些情況下,個(gè)體開(kāi)發(fā)人員使用象 Rational Purify 、Quantify 和 PureCoverage 這樣的工具為他們的單元測試工作提供補充。其他的工具,比如 Rational Robot ,則需要集成與測試團隊具有更高的技能并投入更大的注意力。
團隊仍然必須在系統級別上承擔集成和測試的任務(wù)。多數的單元測試工作被分包給了開(kāi)發(fā)人員,但是我們還需要更加全面和正式的測試子系統和整個(gè)系統。這就意味著(zhù)我們需要正式的構建版本、最終的構建文檔和在集成與測試上的重要關(guān)注。特定目的的負載測試只是我們測試工作中的一小部分,但是它在整個(gè)系統的測試中卻是非常重要的。幸運的是,我們的測試集合已經(jīng)完成了 95% ,并且我們還稍稍的比計劃的時(shí)間提前了一點(diǎn),因此我們能夠有一些額外的精力來(lái)關(guān)注系統的測試以確保高質(zhì)量的第一階段的系統交付。
我們的風(fēng)險列表在此刻已經(jīng)非常的短了??蛻?hù)在演進(jìn)系統上的合作并不太令人驚訝,我們的技術(shù)風(fēng)險已經(jīng)非常少了,非常感謝工程團隊帶來(lái)的良好的進(jìn)展。
現在我們必須對我們的代碼開(kāi)發(fā)進(jìn)行最后的加工、執行系統的測試、識別系統中的任何缺陷并按計劃交付階段一的系統給客戶(hù)。當團隊接近主要階段的尾聲時(shí),及時(shí)的將所有的細節包裝起來(lái)通常時(shí)很難的。如果我們想避免超出計劃,我們就需要系統有少量的缺陷,并且能夠快速的矯正在測試中發(fā)現的任何問(wèn)題。
Steven Franklin 在軟件的設計、架構和工程過(guò)程方面有非常廣泛的背景,這些經(jīng)驗通常被用到大的,分布式的信息管理和控制系統中。他從1997年開(kāi)始使用 Rational 工具,他主要的興趣在 XML 、J2EE、無(wú)線(xiàn)和軟件工程技術(shù)方面。你可以通過(guò)
steve@sfranklin.net聯(lián)系 Steven.