JUnit 簡介
JUnit 是一個開源的單元測試框架,用於編寫和運行自動測試,由 Erich Gamma 和 Kent Beck 在 1997 年開發完成。它包括以下特性:
提供的 API 可以讓你寫出測試結果明確的可重用單元測試用例;
提供了三種方式來顯示你的測試結果,而且還可以擴展;
提供了單元測試用例成批運行的功能;
超輕量級而且使用簡單,沒有商業性的欺騙和無用的向導;
整個框架設計良好,易擴展。
InstallAnywhere 簡介
InstallAnywhere(下文簡稱 IA)是一種多平台安裝程序的開發工具,可用於將桌面系統、企業、或多模式 Web 服務等軟件安裝在任何平台上,並對這些應用程序進行配置,以獲得最佳的性能。它包括以下特性:
支持多平台與多語言,可在任何客戶端或服務器平台部署軟件;
集成開發環境,簡化安裝開發與創造;
支持安裝程序的個性化定制與優化;
實現軟件部署的簡化和標准化,降低測試與支持的成本。
由於安裝程序自身的特點,對它進行自動測試一直是一個難題。對 IA 的前身 InstallShield 來說,一直沒有好的方法將 JUnit 應用到安裝程序的自動測試。IA 提供了這樣的一個框架,使我們可以應用 JUnit 對安裝程序進行自動測試,並且給我們留下對它進行擴展的可能性。本文就將對它進行剖析。
InstallAnywhere 安裝程序圖形界面自動測試框架結構
基於 Swing/AWT 的圖形界面程序的自動測試對開發者來說一直是一個挑戰,這是由於:
底層圖形框架的復雜性。
應用的業務邏輯與圖形界面相結合造成的復雜性。
缺少直觀的自動測試框架。
對基於 InstallAnywhere 開發的安裝程序界面進行自動測試同樣面臨這些問題。前兩個情況是一直都存在的,本文重點研究第三種情況。設計一個安裝程序界面自動測試框架需要解決以下問題:
自動跟蹤測試每一個窗口和面板。
自動測試每個面板上的控件,如文本框、下拉列表、按鈕等。
IA 提供了一個基於 JUnit 3 的安裝程序界面自動測試框架,基於它我們可以方便的編寫測試程序對安裝程序界面進行自動單元測試。IA 圖形界面自動測試框架提供了 4 種 fixture:工作目錄 fixture、臨時目錄 fixture、JAVA 程序執行 fixture,和界面自動測試 fixture。工作目錄和臨時目錄 fixture 分別用於創建工作目錄和臨時目錄。JAVA 程序執行 fixture 用於執行使用 IA 開發的安裝程序。
圖形界面自動測試 fixture 是整個架構的核心,下面將對它進行詳細介紹。
圖 1. IA 圖形界面自動測試框架架構圖
如圖 1 所示界面自動測試 Fixture 由測試用例控制器,事件通知服務器和自測試機器人組成。測試用例控制器定義並控制測試用例。測試用例包括要測試的窗口和面板序列,以及系統輸入事件用來測試面板上每個控件。事件通知服務器監聽安裝程序窗口激活(windows.active)和面板顯示 (panel.show) 事件。自測試機器人產生系統輸入,如按鍵,點擊鼠標等。
測試開始時,此測試框架先創建事件通知服務器。事件通知服務器是一個 socket 服務器,它監聽來自 IA 安裝程序的事件,IA 安裝程序啟動一個窗口以及顯示一個面板都會向事件通知服務器發送一個事件通知。然後 JAVA 程序執行 fixture 啟動 IA 安裝程序。接下來,測試用例控制器會根據事先定義好的測試用例按照線性順序接收來自 IA 安裝程序的事件和向 IA 安裝程序發送系統輸入,直到所有測試完成。
在下一節,本文將舉例說明如何使用 IA 安裝程序圖形界面自動測試框架。
舉例說明如何使用 IA 安裝程序圖形界面自動測試框架
本文用一個使用 IA 開發的安裝程序演示如何使用本文介紹的測試框架。此安裝程序包括三個面板 :Introduction, Choose Install Folders 和 Install Complete(圖 2-4),安裝程序會創建用戶指定的安裝路徑,並將一個文件復制到安裝路徑。測試內容包括:窗口是否被成功打開,面板是否被成功顯示,安裝程序是否正確響應了系統事件,如點擊按鈕,輸入字母等。
圖 2. 面板 Introduction
圖 3. 面板 Choose Install Folders
圖 4. 面板 Install Complete
應用本文介紹的框架,對它進行自動化單元測試變得很簡單。要使用 IA 提供的測試框架,要把 IA 的自動測試庫文件 ia-gui-test-auto.jar 加入到 CLASSPATH 中,你可以在 $IAHOME$ \gui-test-auto\lib 中找到它。接下來編寫測試程序,首先你要繼承 GUIAutomationFixture 編寫自己的測試程序,GUIAutomationFixture 實現了上一節所講的圖形界面自動測試 fixture。
public class BasicProjectAutomation extends GUIAutomationFixture
然後你要編寫測試方法,測試方法要做下面三件事情:
指定執行的安裝程序;
執行測試用例;
設置斷言,檢查程序安裝是否成功。
清單 1. 編寫測試方法
1) String NEW_LOCATION = "newlocation";
2) String productName = "BasicProject";
3) String buildOutput = "_Build_Output/Web_Installers/InstData/Java";
4) File installer = new File("./" + productName + buildOutput, "install.jar");
5) File installDir = new File("C:/Program Files",NEW_LOCATION);
6)
7) setWaitTimeout(30 * SECONDS);
8)
9) runInstall(productName, installer);
10) assertInstallerHasCompletedSuccessfully();
11) assertTrue("Install dir should have been created.", installDir.exists());
12) assertTrue("file-to-install.txt", new File(installDir,
"file-to-install.txt").exists());
清單 1 中第 2-5 行指定要執行的安裝程序,第 9 行執行測試用例,第 10-12 行設置斷言,檢查程序安裝是否成功。第 10 行檢查安裝程序是否正常退出,第 11 行檢查安裝目錄是否創建成功,第 12 行檢查 file-to-install.txt 是否被復制到安裝目錄中。
測試用例定義了要測試的面板以及發送給安裝程序的系統事件,如以下清單 2 所示。
清單 2. 編寫測試用例
1) private void runInstall(String productName, File installer) {
2) try {
3) launchInstaller(installer.getPath());
4)
5) waitForWindow(productName);
6) waitForPanel("Introduction");
7) pressEnter();
8)
9) waitForPanel("Choose Install Folder");
10) pressTab();
11) for (int i = 0; i < productName.length(); i++) {
12) pressKey(KeyEvent.VK_BACK_SPACE);
13) }
14) type(NEW_LOCATION);
15) waitForPanel("Install Complete");
16) pressEnter();
17)
18) waitForInstallerToComplete();
19) } finally {
20) printJavaOutput("Installer");
21) }
22) }
清單 2 中第 3 行啟動待測試的安裝程序。清單 2 中 waitForWindow 及 waitForPanel 方法從事件通知服務器中獲取從安裝程序傳來的事件,其中窗口事件定義為 window.activated:WINDOWS_NAME,面板顯示事件定義為:panel.shown:PANEL_NAME 如果在預定的事件內沒有接收到相應的事件,就拋出異常退出程序。清單 2 中 pressTab, pressKey,type press 及 Enter 方法通知自測試機器人向安裝程序發送按鍵及點擊鼠標等系統事件。例如清單 2 中第 10-14 行修改了 Choose Install Folders 面板中的安裝路徑。
對 IA 安裝程序圖形界面自動測試框架的擴展
IA 提供的圖形界面自動測試框架也存在以下不足:
不能對用戶自定義的面板進行測試;
不能對用戶自定義的業務邏輯進行測試;
由於測試案例采用 java 程序編寫,此框架不適合用於測試復雜的安裝程序。
基於 IA 提供的框架,本文通過擴展事件通知服務器所接收的事件類型來實現對用戶自定義的面板和業務邏輯的測試。並且定義了 XML 格式的測試腳本,用來編寫復雜的測試案例,這樣開發者可以集中注意力在測試案例的編寫上,不用考慮 Java 語法問題,這樣就解決了第三個問題。
首先說明如何通過擴展事件通知服務器所接收的事件類型來實現對用戶自定義的面板和業務邏輯的測試。用戶自定義的面板顯示事件定義為 cuspanel.shown:PANEL_NAME,用戶自定義的業務邏輯事件定義為 cuscode:active:CUSCODE_NAME。代碼如以下清單 3 所示。
清單 3. 擴展事件通知服務器
1) protected void waitForCusPanel(String s)
2) {
3) waitForEvent("cuspanel.shown:" + s);
4) }
5)
6) protected void waitForCusCode(String s)
7) {
8) waitForEvent("cuscode:active:" + s);
9) }
在用戶自定義的面板和業務邏輯要向事件通知服務器發送相應的事件,如以下清單 4 為用戶自定義的面板向事件通知服務器發送面板顯示事件。
清單 4. 用戶自定義的面板向事件通知服務器發送面板顯示事件
1) Socket connectToServer=new Socket(server,12060);
2) OutputStreamWriter ow = new OutputStreamWriter(connectToServer.getOutputStream());
3) ow.write("panel.shown:TestCustomerCodePanel");
4) ow.flush();
5) ow.close();
6) connectToServer.close();
接下來說明如何采用 XML 格式的測試腳本描述測試案例,並且改進測試案例控制器去解析並自動執行測試腳本。擴展後的 IA 安裝程序圖形界面自動測試框架如下圖所示:
圖 5. 擴展後的 IA 安裝程序圖形界面自動測試框架架構圖
描述測試案例的 XML 文檔結構如下表所示。
表 1. 測試案例腳本的文檔結構
節點 子節點 屬性 Product install,uninstall installer Path Install presenter, pressTab, type,清單 2 中所示的測試案例可以用以下清單 5 中的測試案例腳本代替:
清單 5. 測試案例腳本
1) <?xml version="1.0" encoding="UTF-8"?>
2) <Product name="BasicProject" installer="install.jar"
3) buildOutput="_Build_Output/Web_Installers/InstData/Java">
4) <install>
5) <waitForWindow>BasicProject</waitForWindow>
6) <waitForPanel>Introduction</waitForPanel>
7) <pressEnter></pressEnter>
8) <waitForPanel>Choose Install Folder</waitForPanel>
9) <pressTab times="1"></pressTab>
10) <pressKey times="12"></pressKey>
11) <type>newlocation</type>
12) <waitForPanel>Install Complete</waitForPanel>
13) <pressEnter></pressEnter>
14) <waitForInstallerToComplete></waitForInstallerToComplete>
15) </install>
16) </Product>
總結
本文介紹了 InstallAnyWhere 提供的基於 JUnit 安裝程序圖形界面自動測試框架,對它進行了深入的剖析,並舉例說明如何應用它。更進一步分析了它的不足,並針對這些不足對它進行進一步的擴展,使它更完善和使用於復雜的安裝程序的自動測試。使之成為將測試驅動開發模式應用到 InstallAnyWhere 開發的基礎。