自動(dòng)測(cè)試可以節(jié)省重復(fù)執(zhí)行相同測(cè)試步驟的 時(shí)間和精力。本文將介紹 jWebUnit,這是一組 Java 類,用于為 Web 應(yīng)用程序開(kāi)發(fā)測(cè)試用例。jWebUnit 是一個(gè)開(kāi)源項(xiàng)目,可以在 BSD 許可下免費(fèi)獲得。我將介紹如何下載 jWebUnit 庫(kù)、配置 Eclipse 平臺(tái)來(lái)開(kāi)發(fā) jWebUnit 測(cè)試用例,以及如何構(gòu)建一個(gè)示例測(cè)試用例。

jWebUnit 簡(jiǎn)介
jWebUnit 以 HttpUnit(一個(gè)進(jìn)行 Web 應(yīng)用程序自動(dòng)測(cè)試的 Java 庫(kù))和 JUnit 單元測(cè)試框架為基礎(chǔ)(請(qǐng)參閱 參考資料)。 jWebUnit 提供了導(dǎo)航 Web 應(yīng)用程序的高級(jí) API,并組合了一組斷言,用它們來(lái)驗(yàn)證鏈接導(dǎo)航、表單輸入項(xiàng)和提交、表格內(nèi)容以及其他典型商務(wù) Web 應(yīng)用程序特性的正確性。 jWebUnit 以 JAR 文件形式提供的,可以很容易地將它插入大多數(shù) IDE 中,jWebUnit 也包含其他必要的庫(kù)。

用 HttpUnit 進(jìn)行測(cè)試
對(duì) Web 應(yīng)用程序自動(dòng)進(jìn)行測(cè)試意味著跳過(guò) Web 瀏覽器,通過(guò)程序來(lái)處理 Web 站點(diǎn)。首先,我要介紹 HttpUnit(JWebUnit 的構(gòu)建塊之一)是如何簡(jiǎn)化這項(xiàng)工作的。HttpUnit 可以模擬幀、JavaScript、頁(yè)面重定向 cookie,等等。在將 HttpUnit 用于 JUnit 時(shí),它可以迅速地對(duì) Web 站點(diǎn)的功能進(jìn)行驗(yàn)證。

清單 1 顯示了一個(gè)用 HttpUnit 編寫(xiě)的測(cè)試用例,它試圖單擊 HttpUnit 主頁(yè)上的“Cookbook”鏈接:

清單 1. 單擊 HttpUnit 主頁(yè)上 Cookbook 鏈接的 HttpUnit 代碼

            1 public class HttpUnitTest {
            2  public static void main(String[] args) {
            3    try {
            4      WebConversation wc = new WebConversation();
            5      WebRequest request =
            new GetMethodWebRequest("http://httpunit.sourceforge.net/index.html");
            6      wc.setProxyServer( "your.proxy.com", 80 );
            7      WebResponse response = wc.getResponse(request);
            8      WebLink httpunitLink =
            response.getFirstMatchingLink(WebLink.MATCH_CONTAINED_TEXT,"Cookbook");
            9      response = httpunitLink.click();
            10      System.out.println("Test successful !!");
            11    } catch (Exception e) {
            12      System.err.println("Exception: " + e);
            13    }
            14  }
            15 }
            

清單 1 中的代碼用 your.proxy.com (第 6 行)連接 Internet。如果存在直接 Internet 連接,那么可以把這個(gè)語(yǔ)句注釋掉。第 8 行的語(yǔ)句在頁(yè)面中搜索包含文本 Cookbook 的 Web 鏈接。第 9 行的語(yǔ)句用于單擊這個(gè)鏈接。如果找到鏈接,那么用戶會(huì)看到 Test Successful !! 這條消息。

用 jWebUnit 進(jìn)行的測(cè)試更簡(jiǎn)單
清單 2 的測(cè)試用例用 jWebUnit API 執(zhí)行和清單 1 相同的任務(wù):

清單 2. 單擊 HttpUnit 主頁(yè)上 Cookbook 鏈接的 jWebUnit 代碼

            1 public class JWebUnitTest extends WebTestCase{
            2  public static void main(String[] args){
            3    junit.textui.TestRunner.run(new TestSuite(JWebUnitTest.class));
            4  }
            5  public void setUp(){
            6    getTestContext().setBaseUrl("http://httpunit.sourceforge.net");
            7    getTestContext().setProxyName("webproxy.watson.ibm.com");
            8    getTestContext().setProxyPort(8080);
            9  }
            10  public void testSearch(){
            11    beginAt("/index.html");
            12    clickLinkWithText("Cookbook");
            13  }
            14 }
            

如果沒(méi)注意清單 2 中特定于 JUnit 的代碼,那么您可以看到,測(cè)試用例現(xiàn)在變得相當(dāng)整潔、簡(jiǎn)練。需要查看的重要的行是第 6 行、第 11 行和第 12 行。在第 6 行,基本 URL 被設(shè)置到 HttpUnit 的主頁(yè)中。第 11 行用相對(duì)路徑 /index.html 連接站點(diǎn)。第 12 行用于單擊頁(yè)面上具有文本 Cookbook 的鏈接。如果鏈接有效,那么 JUnit 會(huì)報(bào)告成功;否則,JUnit 會(huì)報(bào)告異常。

jWebUnit API:進(jìn)一步觀察
每個(gè) jWebUnit 測(cè)試的核心都是 net.sourceforge.jwebunit.WebTestCase 類,它代表測(cè)試用例。每個(gè)測(cè)試用例都必須是從這個(gè)類擴(kuò)展而來(lái)。(net.sourceforge.jwebunit.WebTestCase 類本身則是從 junit.framework.TestCase 類擴(kuò)展而來(lái)的,它在 JUnit 中代表測(cè)試用例。) 表 1 描述了這個(gè)類的一些常用方法:

表 1. net.sourceforge.jwebunit.WebTestCase 類的重要方法
方法 說(shuō)明
public TestContext getTestContext() 得到測(cè)試用例的上下文。可以用它訪問(wèn)像地區(qū)、基本 URL 和 cookie 之類的項(xiàng)目
public void beginAt(String relativeURL) 在相對(duì)于基本 URL 的 URL 處開(kāi)始對(duì)話
public void setWorkingForm(String nameOrId) 與指定的表單開(kāi)始交互。如果當(dāng)前頁(yè)面只有一個(gè)表單,就不需要調(diào)用這個(gè)方法
protected void submit() 提交表單 —— 等同于單擊表單的 提交 按鈕
public void gotoFrame(String frameName) 激活命名幀

另一個(gè)重要的類是 net.sourceforge.jwebunit.TestContext。它為測(cè)試創(chuàng)建上下文。可以用這個(gè)類來(lái)處理像 cookie、會(huì)話和授權(quán)之類的信息。表 2 顯示了這個(gè)類的一些重要方法:

表 2. net.sourceforge.jwebunit.TestContext 類的重要方法
方法 說(shuō)明
public void addCookie(String name, String value) 向測(cè)試上下文中添加 cookie。在 HttpUnitDialog 開(kāi)始時(shí),添加的 cookie 被設(shè)置到 WebConversation
public void setResourceBundleName(String name) 為測(cè)試上下文設(shè)置一個(gè)使用的資源綁定。用于按照 WebTester 中的鍵查找期望的值
public void setProxyName(String proxyName) 為測(cè)試上下文設(shè)置代理服務(wù)器名稱
public void setBaseUrl(String url) 為測(cè)試上下文設(shè)置基本 URL

下載 jWebUnit,在 Eclipse 中配置 jWebUnit
jWebUnit 是用純 Java 代碼實(shí)現(xiàn)的,所以可以以 JAR 文件的形式獲得它 (請(qǐng)參閱 參考資料,從中獲得下載鏈接)。在完成下載之后,請(qǐng)按以下步驟在 Eclipse 平臺(tái)上配置 jWebUnit 庫(kù):

  1. 把下載的文件 jwebunit-1.2.zip 釋放到臨時(shí)目錄中(假設(shè)是 C:\temp)。
  2. 在 Eclipse 中創(chuàng)建新 Java 項(xiàng)目,將其命名為 jWebUnit。
  3. 右擊 Package Explorer 視圖中的 jWebUnit 項(xiàng)目,然后選擇 Properties
  4. 單擊 Java Build Path。單擊 Libraries 標(biāo)簽中的 Add External JARs
  5. 瀏覽到 C:\temp\jwebunit-1.2\lib 目錄,選擇這個(gè)目錄中的所有 JAR 文件。
  6. 單擊 OK

現(xiàn)在可以在 Eclipse 中的 jWebUnit 項(xiàng)目下開(kāi)發(fā) jWebUnit 測(cè)試用例了。

構(gòu)建示例應(yīng)用程序
現(xiàn)在就可以查看 jWebUnit API 的實(shí)際應(yīng)用了。我將帶您研究一個(gè)示例應(yīng)用程序,幫助您更好地理解 jWebUnit 的真正威力。這個(gè)應(yīng)用程序是一個(gè)測(cè)試用例,用于打開(kāi)一個(gè) Google 搜索頁(yè)面并搜索文本 HttpUnit。應(yīng)用程序需要測(cè)試以下場(chǎng)景:

  • 打開(kāi) Google 主頁(yè) http://www.google.com。

  • 確定該頁(yè)包含一個(gè)名為 q 的表單元素。(在 Google 的主頁(yè)上,名為 q 的文本框是接受用戶查詢輸入的文本框。)應(yīng)用程序用這個(gè)元素輸入搜索參數(shù)。

  • 在搜索文本框中輸入字符串 HttpUnit Home,并提交表單。

  • 獲得結(jié)果頁(yè),并確定該頁(yè)面包含的鏈接中包含文本 HttpUnit Home

  • 單擊包含文本 HttpUnit Home 的鏈接。

現(xiàn)在測(cè)試場(chǎng)景已經(jīng)就緒,可以編寫(xiě) Java 應(yīng)用程序,用 jWebUnit 實(shí)現(xiàn)這些需求了。

第一步是聲明一個(gè)從 WebTestCase 擴(kuò)展而來(lái)的類,如清單 3 所示:

清單 3. 聲明測(cè)試用例類

            public class GoogleTest extends WebTestCase {
            static String searchLink = "";
            }
            

正如我在前面提到過(guò)的,jWebUnit 要求每個(gè)測(cè)試用例都是從 WebTestCase 中擴(kuò)展而來(lái)的。searchLink 保存?zhèn)魅氲乃阉鲄?shù)。這個(gè)值以命令行參數(shù)的形式傳遞給測(cè)試用例。

下一步是聲明入口點(diǎn) —— main() 方法,如清單 4 所示:

清單 4. main() 方法

            public static void main(String[] args) {
            searchLink = args[0];
            junit.textui.TestRunner.run(new TestSuite(GoogleTest.class));
            }
            

main() 方法調(diào)用 junit.textui.TestRunner.run() 執(zhí)行 JTest 測(cè)試用例。因?yàn)樾枰\(yùn)行 GoogleTest 測(cè)試用例,所以,作為參數(shù)傳遞給 run() 方法的測(cè)試套件采用 GoogleTest.class 作為參數(shù)。

接下來(lái),JTest 調(diào)用 setUp() 方法來(lái)設(shè)置基本 URL 和代理,如清單 5 所示:

清單 5. 設(shè)置

            public void setUp() {
            getTestContext().setBaseUrl("http://www.google.com");
            getTestContext().setProxyName("proxy.host.com");
            getTestContext().setProxyPort(80);
            }
            

清單 5 把基本 URL 設(shè)置為 http://www.google.com。這意味著測(cè)試用例的啟動(dòng)是相對(duì)于這個(gè) URL 的。下面兩個(gè)語(yǔ)句設(shè)置連接到 Internet 的代理主機(jī)和代理端口。如果是直接連接到 Internet,那么可以忽略代理設(shè)置語(yǔ)句。

現(xiàn)在開(kāi)始瀏覽站點(diǎn)并輸入搜索參數(shù)。清單 6 顯示了訪問(wèn) Web 頁(yè)面,然后測(cè)試所有場(chǎng)景的代碼:

清單 6. 測(cè)試所有場(chǎng)景

            public void testSearch() {
            beginAt("/");
            assertFormElementPresent("q");
            setFormElement("q", "HttpUnit");
            submit("btnG");
            assertLinkPresentWithText(searchLink);
            clickLinkWithText(searchLink);
            }
            

清單 6 的代碼連接到基本 URL,并相對(duì)于 / 開(kāi)始瀏覽。然后它斷定頁(yè)面中包含一個(gè)名為 q 的表單元素 —— q 是 Google 主頁(yè)上查詢輸入文本框的名稱。下一條語(yǔ)句用值 HttpUnit 設(shè)置名為 q 的文本框。再下一條語(yǔ)言提交表單上名為 btnG 的提交按鈕。(在 Google 的主頁(yè)上,名為 btnG 的按鈕是標(biāo)簽為 Google Search 的按鈕。)表單是在這個(gè)對(duì)話中提交的,下一頁(yè)列出搜索結(jié)果。在結(jié)果頁(yè)面上,代碼首先檢查是否有一個(gè)鏈接的文本是 HttpUnit Home。如果該鏈接不存在,那么測(cè)試就以 AssertionFailedError 失敗。如果該鏈接存在,則測(cè)試執(zhí)行的下一個(gè)操作是單擊鏈接。

運(yùn)行示例應(yīng)用程序
現(xiàn)在把示例應(yīng)用程序投入使用當(dāng)中:

  1. 下載示例應(yīng)用程序 j-webunitsample.jar (請(qǐng)參閱 下載)。

  2. 在一個(gè)目錄中解壓縮 j-webunitsample.jar。例如,如果把它釋放到 C:\temp 中,那么就要把源文件和類文件放在 C:\temp\com\jweb\test 中,而 setclasspth.bat 則放在 C:\temp 中。

  3. 編輯 setclasspath.bat:設(shè)置 JAR_BASE 指向包含所有必需 JAR 文件的目錄。例如,如果在 C:\temp 中釋放 jwebunit-1.2.zip 文件,那么將 JAR_BASE 設(shè)置為 C:\temp\jwebunit-1.2\lib。

  4. 打開(kāi)命令行提示符,切換到 C:\temp 目錄。

  5. 執(zhí)行 setclasspath.bat。這會(huì)設(shè)置執(zhí)行測(cè)試用例所需的 CLASSPATH

  6. 用命令 java com.jweb.test.GoogleTest "HttpUnit Home" 運(yùn)行應(yīng)用程序。

示例輸出
在執(zhí)行了測(cè)試用例之后,會(huì)在命令行輸出一個(gè)測(cè)試用例報(bào)告。如果測(cè)試失敗,報(bào)告看起來(lái)如清單 7 中所示:

清單 7. 帶有斷言失敗的輸出

            C:\temp>java com.jweb.test.GoogleTest "HttpUnit Hwee"
            .F
            Time: 5.338
            There was 1 failure:
            1) testSearch(com.jweb.test.GoogleTest)junit.framework.AssertionFailedError: Link
            with text [HttpUnit Hwee] not found in response.
            at net.sourceforge.jwebunit.WebTester.assertLinkPresentWithText(WebTester.java:618)
            at net.sourceforge.jwebunit.WebTestCase.assertLinkPresentWithText(WebTestCase.java:244)
            at com.jweb.test.GoogleTest.testSearch(GoogleTest.java:36)
            at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
            at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
            at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
            at com.jweb.test.GoogleTest.main(GoogleTest.java:19)
            FAILURES!!!
            Tests run: 1,  Failures: 1,  Errors: 0
            

正如在清單 7 中可以看到的,可以用 HttpUnit Hwee 作為參數(shù)來(lái)執(zhí)行測(cè)試用例。這個(gè)測(cè)試用例遇到斷言的地方會(huì)失敗,因?yàn)榻Y(jié)果頁(yè)面中不包含帶有這個(gè)文本的鏈接。由此也就產(chǎn)生了junit.framework.AssertionFailedError

清單 8 執(zhí)行時(shí)用 HttpUnit Home 作為參數(shù)。測(cè)試用例找到一個(gè)帶有這個(gè)文本的鏈接,所以測(cè)試通過(guò)了:

清單 8. 成功測(cè)試的輸出

            C:\temp>java com.jweb.test.GoogleTest "HttpUnit Home"
            .
            Time: 6.991
            OK (1 test)
            

結(jié)束語(yǔ)
本 文通過(guò)討論 jWebUnit 框架的一些突出特性和最重要的類,介紹如何用它創(chuàng)建簡(jiǎn)潔的測(cè)試用例,讓您對(duì) jWebUnit 框架有一個(gè)認(rèn)識(shí)。jWebUnit 還有更多特性可以用在測(cè)試用例中。它支持測(cè)試 Web 頁(yè)面中的鏈接行數(shù)。可以對(duì)字符串、表或者帶有指定標(biāo)簽的表單輸入元素是否存在于頁(yè)面上進(jìn)行斷言。此外,jWebUnit 還可以處理 cookie (例如斷言存在某個(gè) cookie、刪除 cookie 等。)測(cè)試可以對(duì)某個(gè)文本之后出現(xiàn)的特定文本的鏈接進(jìn)行單擊。 如果想為 Web 應(yīng)用程序構(gòu)建快而有效的測(cè)試用例,jWebUnit 可能是您最好的朋友。