圖 1. 創(chuàng)建小部件的 Web 表單
請(qǐng)注意:表單元素的類(lèi)型是具有三個(gè)不同選項(xiàng)的下拉列表,如圖 2 所示:
圖 2. 包含下拉列表的 Web 表單
單擊 Create Widget 將促使 Groovlet 處理這一請(qǐng)求。如果所有內(nèi)容正確的話(huà)(即名字和定義不為空,并且數(shù)據(jù)庫(kù)中不存在該實(shí)例),Groovlet 將創(chuàng)建一個(gè)新的小部件實(shí)例并類(lèi)似圖 3 所示的狀態(tài)頁(yè)面:
圖 3. 返回的 Web 頁(yè)面顯示狀態(tài)
結(jié)合使用 Selenium 和 TestNG 驗(yàn)證簡(jiǎn)單的 Create Widget 用例是一種可管理的應(yīng)用:
配置并啟動(dòng) Selenium 服務(wù)器的實(shí)例。
與 Create Widget Web 表單交互并提交它。
檢驗(yàn)結(jié)果頁(yè)面是否包含具有小部件名稱(chēng)的成功信息。
停止 Selenium 服務(wù)器實(shí)例。
請(qǐng)注意:用例中的每一步都是通過(guò) Selenium 完成的 —— 所以說(shuō),TestNG 僅僅幫助進(jìn)行查找,F(xiàn)在,我們來(lái)實(shí)踐一下。
Create Widget 測(cè)試用例
我希望對(duì) Selenium 服務(wù)器進(jìn)行靈活的配置,所以我將編寫(xiě)一個(gè)參數(shù)化 fixture(TestNG-Selenium 樣式),一般可以使用它來(lái)為不同瀏覽器、不同位置甚至混合的 Web 應(yīng)用程序地址(類(lèi)似 localhost 和產(chǎn)品)創(chuàng)建 Selenium 服務(wù)器。清單 4 定義了我所配置的靈活的 Selenium 服務(wù)器 fixture:
清單 4. 靈活的 Selenium fixture
@Parameters({"selen-svr-addr","brwsr-path","aut-addr"}) @BeforeClass private void init(String selenSrvrAddr, String bpath, String appPath) throws Exception { driver = new DefaultSelenium(selenSrvrAddr, SeleniumServer.getDefaultPort(), bpath, appPath); driver.start(); } //.... @AfterClass private void stop() throws Exception { driver.stop(); }
必須將參數(shù)名與 TestNG 的 testng.xml 文件中的值鏈接起來(lái);因此,我定義了如清單 5 所示的三個(gè)參數(shù)。(默認(rèn)情況下為 Firefox 定義了 brwsr-path 參數(shù),但是我可以同樣輕松地定義一組新的使用 Internet Explorer 的測(cè)試。)
清單 5. TestNG testng.xml 文件中的參數(shù)值
<parameter name="selen-svr-addr" value="localhost"/> <parameter name="aut-addr" value="http://localhost:8080/gt15/"/> <parameter name="brwsr-path" value="*firefox"/>
接下來(lái),我將定義清單 6 所示的測(cè)試用例,它也包含一個(gè)參數(shù),用于進(jìn)行測(cè)試的應(yīng)用程序的基 URL。該測(cè)試將促使瀏覽器在 Web 應(yīng)用程序內(nèi)打開(kāi)特定頁(yè)面,并操作 圖 1 所示的表單。
清單 6. 一個(gè)良好的測(cè)試用例
@Parameters({"aut-addr"}) @Test public void verifyCreate(String appPath) throws Exception { driver.open(appPath + "/CreateWidget.html"); driver.type("widget", "book-01"); driver.select("type", "book"); driver.type("definition", "book widget type book"); driver.click("submit"); driver.waitForPageToLoad("10000"); assertEquals(driver.getText("success"), "The widget book-01 was successfully created.", "test didn't return expected message"); }
通過(guò)調(diào)用 driver.click("submit") 提交表單后,Selenium 將等待響應(yīng)的加載,然后我將斷言成功的創(chuàng)建信息。(注意:響應(yīng) Web 頁(yè)面具有一個(gè) ID 為 success 的元素。)
結(jié)果產(chǎn)生一個(gè)靈活的文本類(lèi),它將檢驗(yàn)兩種場(chǎng)景:一種是良好的場(chǎng)景,而另一種是沒(méi)有提供定義的邊界用例,如清單 7 所示:
清單 7. 使用 TestNG 進(jìn)行全部的處理
public class CreateWidgetUATest { private Selenium driver; @Parameters({"selen-svr-addr","brwsr-path","aut-addr"}) @BeforeClass private void init(String selenSrvrAddr, String bpath, String appPath) throws Exception { driver = new DefaultSelenium(selenSrvrAddr, SeleniumServer.getDefaultPort(), bpath, appPath); driver.start(); } @Parameters({"aut-addr"}) @Test public void verifyCreate(String appPath) throws Exception { driver.open(appPath + "/CreateWidget.html"); driver.type("widget", "book-01"); driver.select("type", "book"); driver.type("definition", "book widget type book"); driver.click("submit"); driver.waitForPageToLoad("10000"); assertEquals(driver.getText("success"), "The widget book-01 was successfully created.", "test didn't return expected message"); } @Parameters({"aut-addr"}) @Test public void verifyCreationError(String appPath) throws Exception { driver.open(appPath + "/CreateWidget.html"); driver.type("widget", "book-02"); driver.select("type", "book"); //definition explicitly set to blank driver.type("definition", ""); driver.click("submit"); driver.waitForPageToLoad("10000"); assertEquals(driver.getText("failure"), "There was an error in creating the widget.", "test didn't return expected message"); } @AfterClass private void stop() throws Exception { driver.stop(); }}
目前為止,我已經(jīng)定義了兩種足夠靈活的 Selenium 測(cè)試,可以對(duì)多個(gè)瀏覽器進(jìn)行測(cè)試,并且還可以對(duì)多個(gè)位置進(jìn)行測(cè)試,這對(duì)初學(xué)者非常有利。盡管如此,我還想獲得更高級(jí)點(diǎn)的應(yīng)用,我開(kāi)始考慮測(cè)試中的邏輯是否可重復(fù)使用。比如,如果對(duì)一行運(yùn)行兩次 CreateWidgetUATest 測(cè)試類(lèi)會(huì)怎樣?如何確保我的 Web 應(yīng)用程序運(yùn)行的是本地機(jī)器(或其他機(jī)器)上新版本的代碼?
可重復(fù)的驗(yàn)收測(cè)試
在執(zhí)行 Selenium 測(cè)試時(shí),必須運(yùn)行 Selenium 服務(wù)器以及要檢驗(yàn)的 Web 應(yīng)用程序。言外之意,還必須運(yùn)行應(yīng)用程序中所有相關(guān)的架構(gòu)依賴(lài)關(guān)系 —— 對(duì)于大多數(shù) Java™ Web 應(yīng)用程序來(lái)說(shuō),即 Servlet 容器和相關(guān)的數(shù)據(jù)庫(kù)。
正如在我的另一篇文章 repeatable system tests 中解釋的一樣,DbUnit 和 Cargo 是兩種我喜歡的技術(shù),可以在依賴(lài)數(shù)據(jù)庫(kù)的 Web 應(yīng)用程序中實(shí)現(xiàn)邏輯重復(fù)。DbUnit 管理數(shù)據(jù)庫(kù)中的數(shù)據(jù),而 Cargo 使容器管理以通用的方式實(shí)現(xiàn)自動(dòng)化。下面幾節(jié)將向您展示如何結(jié)合使用 Selenium 和 TestNG 從而確保實(shí)現(xiàn)邏輯重復(fù)的驗(yàn)收測(cè)試。