2011年6月23日 星期四

測試自動化

http://www.ithome.com.tw/itadm/article.php?c=68212

文/陳宏一 2011-06-22

當建構自動化作業整合到CI伺服器時,為提升軟體品質,接下來便是落實軟體測試作業自動化


要達到持續整合中所提到持續且不斷改善,沒有理由不利用自動化方式來進行這些重複且標準化的作業。在《軟體測試之道—微軟測試團隊的成功經驗、方法與技 術》一書中提到,光Office 2007這套軟體就包含超過百萬個測試案例,相信微軟工程師勢必結合高效率之自動化方式,才能在有限時間內完成這項偉大的測試工作。

測試自動化對既有作業的影響
記得中學國文課本的《指喻》,意謂著問題修復的成本會因時間歷程愈久而愈高。測試自動化作業便是以化整為零的概念,將過去開發階段所獨立定義的測試階段,打散部分的工作提前到開發建構階段來處理,早期發現早期治療。

要落實測試自動化,接下來必須面臨的現實問題就是需要撰寫額外的測試程式。直接反應到開發人員所需要額外花費的工時。然而實務上常因時程與人力不足的現實限制而讓測試程式碼的撰寫大打折扣,進而讓測試作業無法發揮測試應有的效益。

對於測試程式的撰寫方式,大多是將主程式的元件及服務都撰寫完畢後,再來撰寫測試案例。實務上常會因為時程的壓縮造成撰寫測試案例的時間被省略掉,以致未 能達到良好的測試。敏捷(Agile)製程中的測試導向開發(TDD),則是強調先撰寫測試程式,再逐步衍生出主要的核心元件及服務,不斷地改寫原本的主 程式來符合測試程式的結果。

是否採用TDD引起不少討論,就筆者面臨的實務經驗及現今企業的組織分工狀況,不見得能順利落實。像是具有專責測試人員或單位編制的企業,其主程式與測試程式的開發人員不是同一人時,就不易進行先測試再寫主程式代碼的方式。

然而開發工具的支援也是相當現實的問題,像目前微軟Visual Studio 2010可支援撰寫測試程式的當下,同時產生尚未開發的主程式類別屬性及方法,就更能貼近TDD的想法,否則只是讓開發人員因為測試無法進行而又回到原始做法。

軟體測試型態及使用時機
在軟體工程中所定義的軟體測試類型的種類繁多,但就實務上因專案時程與人力資源的限制,通常會選擇重要且必然被重複執行的項目來要求。

● 單元測試(Unit Test)
是針對單一元件本身的設計進行測試,以確保最小單位的處理邏輯是正確無誤。檢測方式主要是針對元件提供的方法進行輸入及輸出的驗證,以確保內部處理邏輯的 正確性。就單元測試本身的特性是輕薄短小,為了發揮物件化設計的精神,高內聚力低耦合力的元件架構下,單一元件的測試作業是相當輕快的。而這個測試的執行 可以整合於建構平臺中,每當有任何程式被異動交付(commit)時隨即進行,可及時檢測。

● 功能測試(Functional Test)
它會結合多項元件針對特定功能聯合檢測,範圍會是著重在特定子功能模組或是,其測試步驟可能會有前後相依性,單一測試案例的時間及複雜度都較單元測試為高。視情況在CI伺服器上設置定期排程方式,進行自動測試作業。

● 系統整合測試(System Test)
由於測試的範圍及花費時間較單元測試為長,一般都在每日建構作業啟動時或下班時間進行,以避免在測試時造成的系統負荷及其他開發作業影響。

● 迴歸測試(Regression Test)
可以避免既有功能因新版本的釋出而發生錯誤。軟體功能相依性無法完全避免,程式碼只要異動,可能會引發連帶影響,若能在異動當下即能確保相關功能是否通過 測試檢驗,由於功能因版本變更而持續增加,這部分的測試程式亦是不斷累積日趨成熟,可被持續重用,除非原本功能及處理邏輯已被異動。

● 效能壓力測試(Performance and Stress Test)
針對主程式在上述相關測試工作都已經完畢,結合正式環境或擬真環境來進行系統效能及壓力承受度的檢測。此類測試的結果會因系統執行環境的狀況而有不同結 果。一般而言是針對每個測試案例或測試計畫來統計平均需要花費的時間有多少,供管理者評判該數值的合理性;而壓力測試則必須以正式環境,所得數據才有參考 價值。

● 測試涵蓋度的監控 (Coverage)
因為軟體功能的日益強化,相關測試程式的數量也是不斷增加,就測試範疇多少會有漏測或是重覆測試的情況出現,搭配測試涵蓋度的工具來同步監控,能清楚掌握 主程式被實際測試的廣度及深度為何,進而調整測試程式內容。選用的涵蓋度監控工具必須與你所採用的測試框架能整合互通,才能發揮效益。

測試自動化的實務規畫設計
在撰寫測試程式時如何運用良好的設計思維,來讓繁雜的測試程式代碼更易於使用及管理?

● 既有開源資源的引用
針對軟體測試的開源框架已經相當成熟,因應不同測試領域而有多種成熟的解決方案可供採用。這些框架容易學習便於上手,亦提供完整的測試結果報告。常見的像 是著重在單元及功能測試的JUnit、NUnit,針對資料庫存取進行資料驗證的DBUnit;運用在Web Server測試,檢證XML資料格式的XMLUnit; 模擬瀏覽器操作行為,針對網站應用程式測試的Selenium;還有,HTTP通訊協定測試的HttpUnit、針對J2EE應用程式整合測試的 Cactus、提供效能及壓力監測的JMeter、JUnitPerf,以及測試涵蓋度監控的Quilt、Cobertura,與程式碼靜態掃描的 Findbugs、Lint等。

● 測試程式獨立規畫
原則上針對主程式所撰寫的測試程式,亦會依照所測試標的及類別,分別以不同的套件package及類別class來設計撰寫,而不混用在現有的主程式之 中,以便於因為不同建構階段執行不同測試自動化內容,及整合建構自動化之管理。例如會以獨立命名一套package;而每個測試案例亦必須都能單獨運作, 減少測試程式之間的耦合程度。

● 測試程式代碼的快速產生
不管你是用何種方式來撰寫測試案例,運用良好的測試框架,結會既有開發工具來輔助測試程式代碼的快速生成是相當重要的。由於撰寫測試程式的代碼實屬枯燥粗 活,若可妥善利用程式碼產生工具亦可協助減少撰寫所耗費的時間。例如利用Eclipse IDE內建JUnit plug-in建立單元測試元件;WTTools開源專案裡的UnitTestGen,可整合在建構腳本中自動化產生JUnit對應測試程式碼,並同時進 行單元測試作業;商業軟體Parasoft亦針對不同程式語言提供像是JTest或c++ Test等工具以利輔助。

● 彈性設計方式,減少修改的頻率及幅度
由於主程式的不斷發展,測試程式亦得隨之更動測試內容及測試範圍,新增了一個方法,修改了一個傳入參數,對應的測試程式都很再調整,如此一來暴增的工作使 得開發及測試更無法兼顧。像是利用Java Reflection的方式,在測試案例的撰寫時自動找尋應測之方法有那些而逐一檢測,或是導入類似OpenPojo測試框架來處理單一pojo或 entity物件的測試,亦能單純化測試程式的撰寫。

● 與持續整合平臺無縫結合
已撰寫完畢的測試程式,不是只單純利用IDE方式執行即可,最終需要結合CI伺服器平臺,依實際需求來決定各項測試作業執行的時間點,可支援指定排程自動 啟動(Scheduled Automation),程式碼交付即自動啟動(Trigger Automation),並針對測試結果即時透過通報機制分派問題及修復錯誤,如此才能真正做到持續整合的精神。