selenium1.X web Test experience

簡介javascript

Selenium 是一個健壯的工具集合,跨不少平臺支持針對基於 web 的應用程序的測試自動化的敏捷開發。它是一個開源的、輕量級的自動化工具,很容易集成到各類項目中,支持多種編程語言,好比 .NET、Perl、Python、Ruby 和 Java™ 編程語言。css

利用 Selenium 測試 Ajax 應用程序java

Asynchronous JavaScript and XML (Ajax) 是一種用於建立交互式 web 應用程序的 web 開發技術。Ajax 應用程序的一個特徵是,不會致使一次從新加載整個頁面。相反,瀏覽器將具備一個對服務器的異步調用以得到數據,而且只刷新當前頁面的特定部分。要提升 web 頁面的交互性、響應速度和可用性,測試 Ajax 應用程序的過程須要一些改變。web

咱們首先刷新 web 頁面,而後就是等待,直到異步調用完成。完成以後,能夠繼續進行驗證。此時,出現適當等待時間的問題。chrome

一種選擇是在測試應用程序中簡單地暫停一段固定的時間,這在大多數狀況下都是可行的。在有些狀況下,好比說網絡吞吐量很慢時,Ajax 調用在暫停一段特定的時間以後沒有完成,會致使測試用例失敗。另外一方面,若是暫停時間太長,會使得測試慢得不可接受。express

Selenium 提供了更爲高效的處理等待的方式。一種可能作法是,使用類 com.thoughtworks.selenium.Wait 來等待一個元素或文本在頁面上出現或消失。能夠在 until() 函數中定義等待的退出條件,或者擴展 Wait 類來實現等待退出。清單 1 是使用 Wait 類的樣例代碼。它將在條件知足時中止等待,或者在超出最大等待時間時返回一個超時異常。編程


清單 1. 等待元素或文本出現瀏覽器

Wait wait = new Wait() {
	public boolean until() {
	return selenium.isElementPresent(locator);
	// or selenium.isTextPresent(pattern);
	}
};
wait.wait("", timeoutInMilliseconds);

 

另外一種選擇是使用 Selenium 中的 waitForCondition 函數,一個 JavaScript 代碼片斷將被做爲參數傳遞給該函數。一旦 Selenium 檢測到條件返回爲真,它將中止等待。您能夠等待一些元素或文本出現或者不出現。JavaScript 能夠運行在由 Selenium.browser.getCurrentWindow() 函數彈出的應用程序窗口中。清單 2 是檢查窗口狀態的樣例代碼。它只工做在 Firefox 中。安全


清單 2. 等待窗口就緒的狀態服務器

String script = "var my_window = selenium.browserbot.getCurrentWindow();" 
script += "var bool;";
 script += "var readyState = (my_window.document.readyState);";
script += "if (readyState == 'complete'){";
script += "bool = 'true';";
script += "}";
script += "bool;";
selenium.waitForCondition(script, timeoutInMilliseconds);

如何支持 dojo 應用程序

Dojo 是一個經常使用的 JavaScript 工具包,用於構造動態 web 界面。使用 Selenium 測試 Dojo 應用程序時的一個關鍵點是認識 Dojo 小部件和記錄它們的操做。做者定義的 Dojo 小部件處於抽象級別。頁面運行時,會將 Dojo 小部件轉換成基本的 HTML 代碼。存在不少由 Dojo 自動生成的 HTML 代碼,所以,Dojo 小部件的認識可能與傳統 HTML 小部件有些不一樣。

Dojo 小部件上執行的操做(包括文本字段、按鈕複選框和單選按鈕)可能與 HTML 小部件相同。可是,Dojo 在組合框上提供的日期選擇器和其餘額外的小部件可能須要特定的處理。


圖 1. Dojo 組合框
展現帶幾個選項的組合框的屏幕快照

使用 Selenium IDE 來記錄圖 1 中提供的組合框上選中的操做。單擊向下箭頭,會出現一個下拉列表。選中第三項 Stack(SWG)。記錄的腳本提供在圖 2 中。


圖 2. Selenium IDE 記錄的腳本
展現 Selenium 所記錄信息(好比鼠標單擊)的屏幕快照

有時,只會由 IDE 生成第二行腳本。在這種狀況下,添加單擊箭頭按鈕的操做。對於上面的腳本,若是第一行被從新播放,那麼它應該生成下拉列表。可是它不執行任何操做。對於多個 Dojo 小部件,單擊並不真正執行單擊操做。將 click(locator) 更改成 clickAt(locator, coordString) 或者 MouseDown(locator)MouseUp(locator)。

對於下拉列表,等待時間應該相加。像圖 2 中展現的腳本同樣,選中項的單擊操做將會恰好在單擊向下箭頭按鈕以後執行。它可能會由於下拉列表沒有出現而失敗。簡單地添加一個 pause 命令,或者使用 waitFor 命令等待菜單項元素出現,並繼續執行下一個命令。

修改後的將會自動化 Dojo 組合框上的選擇的腳本展現在圖 3 中。


圖 3. 修改後的在 Dojo 組合框中進行選擇的 IDE 腳本
屏幕快照展現 clickAt、waitForElement 和 ClickAt 命令已修改

RC 代碼展現在清單 3 中。


清單 3. 自動化 Dojo 組合框中選擇操做的 RC 代碼

selenium.clickAt("//div[@id='widget_offeringType']/div/div",」」);
selenium.waitForCondition("selenium.isElementPresent(\"offeringType_popup2\")", "2000");
selenium.clickAt("offeringType_popup2",」」);



圖 4. 日期選擇器
展現日期選擇器的常規月曆視圖的屏幕快照

對於圖 4 中的日期選擇器例子,執行的操做可能不會被 IDE 記錄。編寫以下面清單 4 所示的 RC 代碼。


清單 4. 自動化選擇的 RC 代碼

//click on the date field by id you defined;
selenium.clickAt("dateBox",""); 
//wait for the drop down date box by id;
selenium.waitForCondition("selenium.isElementPresent(\"widget_dateBox_dropdown\")", \
"2000"); 
//click previous year 2008;
selenium.clickAt("//span[contains(@class,'dijitCalendarPreviousYear')]", "");
//click on the month increase; 
//previous month would contains  ‘dijitCalendarIncrease’.
selenium.clickAt("//img[contains(@class,'dijitCalendarIncrease')]","");
//click on the date such as 28 of current month; If you do not specify 
//the td with the attribute of current month class, it will click \
on the //first 28 of previous month;
selenium.click("//td[contains(@class,'dijitCalendarCurrentMonth')]/span[text()='28']");

 

如本例所示,Dojo 應用程序不能經過簡單的 IDE 記錄進行測試。這些腳本有可能不能經過測試。腳本中有一些丟失的操做,或者操做並不真正工做。腳本應該調整成可以在 IDE 和 RC 中順利地執行。對於複雜的 Dojo 小部件,一種可能的解決方案是使用 runScript(String) 函數,由於 Selenium 對 JavaScript 提供很好的支持。清單 5 提供一個 JavaScript 語句來模擬組合框選擇。


清單 5. 運行 JavaScript 語句在組合框上進行選擇

selenium.runScript("dijit.byId(\"offeringType\").setValue(\"Stack(SWG)");");

如何利用 Ant 構建 Selenium 測試

諸如 Ant 這樣的集成工具能夠方便地構建 Selenium 測試和順暢地運行測試用例,無需單獨啓動 Selenium 服務器。若是 Selenium 測試由 TestNG 驅動,那麼定義清單 6 所示 TestNG Ant 任務。清單 6 中假設 classpath 是 TestNG.jar 文件的文件路徑。


清單 6. TestNG Ant 任務

<taskdef resource="testngtasks" classpath="testng.jar"/>       

 

主要的目標是啓動服務器、運行測試,而後中止服務器。這些任務按照 bulid.xml 中定義的順序實如今清單 7 中。


清單 7. 啓動服務器、運行測試用例並中止服務器的 Ant 任務

<target name="run_test" description="start,run and stop" depends="dist">
<parallel>
 <antcall target="start-server" /> 
<sequential>
 <echo taskname="waitfor" message="Waitforproxy server launch" /> 
 <waitfor maxwait="2" maxwaitunit="minute" checkevery="100">
 <http url="http://localhost:4444/selenium-server/driver/?cmd=testComplete" /> 
 </waitfor>
 <antcall target="runTestNG" /> 
 <antcall target="stop-server" /> 
 </sequential>
 </parallel>
 </target>

 

代碼更可取的地方是使用 waitfor 任務來測試 Selenium 服務器是否已成功啓動,而不是暫停一段固定的時間。若是 URL http://localhost:4444/selenium-server/driver/?cmd=testComplete 可用,就意味着 Selenium 已經成功啓動。在清單 7 中,它最多等待兩分鐘,而且每 100 毫秒在本地主機上檢查一次 Selenium 服務器,以提供完整的 URL。

start-server 任務的詳細內容定義在清單 8 中。Firefox profile 模板位置和其餘參數能夠指定在標記 <arg> 中。


清單 8. 詳細的啓動服務器的 Ant 任務

<target name="start-server">
<java jar="lib/selenium-server.jar" fork="true">
 <arg line="-firefoxProfileTemplate ${selenium}/profile/" /> 
 </java>
 </target>

 

runTestNG 任務的詳細內容定義在清單 9 中。testng 任務的經常使用屬性包括 outputDirxmlfileset。屬性 outputDir 用於設置輸出報告位置。屬性 xmlfileset 用於包含啓動 XML 文件。更多選項請參考 TestNG 正式網站。


清單 9. 運行測試用例的 Ant 任務

<target name="runTestNG">
<testng outputDir="${testng.report.dir}" sourcedir="${build}" 
classpathref="run.cp" haltOnfailure="true">
 <xmlfileset dir="${build}" includes="testng.xml" /> 
 </testng>
 </target>

 

stop-server 任務的詳細內容定義在清單 10 中。


清單 10. 中止 Selenium 服務器的 Ant 任務

<target name="stop-server">
 <get taskname="selenium-shutdown" 
src="http://localhost:4444/selenium-server/driver/?cmd=shutDown" ignoreerrors="true" /> 
 <echo taskname="selenium-shutdown" message=" Errors during shutdown are expected" /> 
 </target>

 

上面列出了關鍵任務。將它們組合到您的構建文件,以便利用 Ant 完成良好集成的測試。

如何支持測試 HTTPS 網站

隨着互聯網日益強調信息安全,愈來愈多的 web 應用程序在使用 SSL 身份認證。Selenium IDE 默認支持 HTTPS,可是 Selenium RC 不是這樣的。Internet Explorer 和 Firefox 中的解決方案各不相同。

對於 IE,在 setup 目錄下的 SSL 支持文件夾中在安裝一個證書。若是使用的版本早於 Selenium-RC 1.0 beta 2,請使用 *iehta 運行模式,對於 Selenium-RC 1.0 beta 2 或更晚的版本,使用 *iexplore 運行模式。

若是測試 HTTPS 網站時出現一個以下所示的安全警告,那麼單擊 View Certificate 並安裝 HTTPS 網站的證書。若是繼續彈出警告,那麼考慮在 IE 中進行配置。打開 Tool > Internet Options > Advanced,並取消選擇 security 分類下的 Warn about invalid site certificatesCheck for publisher's certificate revocation


圖 5. 測試 HTTPS 網站時的安全警告
展現指出證書未證明的 Security Alert 的屏幕快照

建立新的 Firefox 配置文件

對於 Firefox,遵循如下步驟建立定製的配置文件,而後重啓服務器:

  1. 關閉任何正在運行的 Firefox 實例。
  2. 利用配置文件管理器 firefox -ProfileManager 啓動 Firefox。
  3. 建立一個新的配置文件。出現提示時,爲配置文件選擇一個目錄。將它放在項目文件夾裏面。
  4. 選擇配置文件並運行 Firefox。
  5. 利用您將用於測試的自簽名證書導航到 HTTPS URL。 出現提示時接受證書。這將在配置文件中建立一個異常。
  6. 關閉瀏覽器。
  7. 轉到 Firefox 配置文件目錄。
  8. 刪除該目錄中除 cert_override.txtcert8.db 文件以外的任何東西。

默認狀況下,Selenium 將在啓動 Firefox 的實例時建立一個新的配置文件。當您利用參數 -firefoxProfileTemplate /path/to/profile/dir 啓動服務器時,Selenium 將使用一個部分配置文件(帶有證書異常)做爲建立新配置文件的基礎。這將提供證書異常,而避免了使用整個配置文件帶來額外的混亂。注意一下在 Selenium RC 1.0 Beta 2 或更晚版本中以 *firefox 模式,以及在 Selenium RC 1.0 Beta 2 以前的版本中以 *chrome 模式啓動 Firefox。

對於運行模式,*chrome*iehta 是較早版本 Selenium RC 中支持 HTTPS 和安全彈出處理的實驗模式。自 Selenium-RC 1.0 beta 2 起,它們已經穩定成 *firefox*iexplore 運行模式。請謹慎地根據所使用的 Selenium 版本而使用運行模式。

如何高效地認識不帶 ID 屬性的 web 元素

使用一個有含義的 ID 或名稱是一種高效且方便的定位元素的方式。它也能夠改善測試用例的可讀性。可是爲了每一個元素具備一個有含義的、唯一的 ID(尤爲是動態元素),Selenium 提供多種策略來認識元素,好比說 Xpath、DOM 和 CSS。

下面是一個樣例,使用三種策略來定位圖 6 中提供的動態表格中的一個元素。HTML 代碼在清單 11 中。


圖 6. 動態表格樣例
展現動態建立的簡單表格(帶有兩列和編輯連接)的屏幕快照


清單 11. 第一個表格列的 HTML 代碼

<table id="test_table" border="1">
		<tbody>
        <tr>
            <td align="left">
                <div class="test_class">Test 1</div>
            </td>
            <td align="center" style="vertical-align: top;">
                <table id="AUTOGENBOOKMARK_4">
                    <tbody>
                        <tr>
                            <td align="center" style="vertical-align: top;">
                                <div>
                                  <img alt="supported" src="supported.png"/>
                                </div>
                            </td>
                            <td align="center" style="vertical-align: top;">
                                <div>
                                   <a href="test?name=test1">edit</a>
                                </div>
                            </td>
	…….

 

Xpath 是一種找到不帶特定 ID 或名稱的元素的簡單方式。

  • 若是知道 ID 或名稱以外的一個屬性,那麼直接使用 @attribute=value 定位元素。
  • 若是隻知道屬性值的一些特定部分,那麼使用 contains(attribute, value) 定位元素。
  • 若是元素沒有指定的屬性,那麼利用 Firebug 搜索最近的具備指定屬性的父元素,而後使用 Xpath 從這個元素開始定位想要找到的那個元素。


表 1. 定位元素的 Xpath 表達式

定位元素 Xpath 表達式
n 行的第一列 //table[@id='test_table']//tr[n]/td
n 行的圖像 //table[@id='test_table']//tr[n]//img
‘Test 1’ 的編輯連接 //a[contains(@href,test1)]

 

表 1 展現了定位元素的 Xpath 表達式。在 Firebug 的幫助下,Xpath 能夠定位元素和複製的元素。在元素沒有 ID 和名稱時,Selenium IDE 將會採用 Xpath。儘管 Xpath 利用已經錄的腳本,有助於保持一致性,可是它高度依賴於 web 頁面的結構。這使得測試用例可讀性差,增長了維護難度。此外,在 Internet Explorer 7 和 Internet Explorer 8 中運行具備多個複雜 Xpath 表達式的測試用例可能會太慢了。在這種狀況下,將 Xpath 更換爲 DOM,後者是另外一種高效的定位策略。

DOM 是 Document Object Model(文檔對象模型)的縮寫。Selenium 容許您利用 JavaScript 遍歷 HTML DOM。Java 的靈活性容許在 DOM 表達式中有多個語句,用分號隔開,以及在語句中定義函數。


表 2. 定位元素的 DOM 表達式

定位元素 DOM 表達式
n 行的第一列 dom=document.getElementById('test_table').rows[n-1].cells[0]
n 行的圖像 dom=element=document.getElementById('test_table').rows[n-1].cells[1]; element.getElementsByTagName('IMG')[0]
‘Test 1’ 的編輯連接
dom=function test(){
var array=document.getElementsByTagName('a');
var element;for(var i=0; i<array.length; i++)
{if(array[i].attributes.getNamedItem("href").\
value.indexOf('test2')!=-1){element=array[i];break;}}return element}; test()

 

表 2 展現了定位元素的 DOM 表達式。DOM 定位器在 Firefox 和 Internet Explorer 中也有很好的性能。組織 DOM 表達式須要一些 JavaScript 知識。有時,DOM 表達式對於複雜的元素來講太長了,難以看懂(參見表 2 中提到的 Test 1 的編輯連接的表達式)。

CSS 定位器用於利用 CSS 選擇器選擇元素。當 HTML 代碼具備良好的樣式時,能夠高效地利用 CSS 定位器。樣例表達式展現在表 3 中。


表 3. 定位元素的 CSS 表達式

定位元素 CSS 表達式
n 行的第一列 css=#test_table .test_class:nth-child(n)
n 行的圖像
css=#test_table  tr:nth-child(n) > td:nth-child(2) > 
table td:nth-child(1) > div >  img

‘Test 1’ 的編輯連接 css=a[href*='test2']

 

通常來講,選用熟悉的定位器表達式,並在腳本結構中保持一致。若是有多種表達式可執行,那麼使用最高效的方式在 web 頁面中定位元素。

如何處理彈出窗口

通常來講,操做都是在由 Selenium 啓動的主窗口中執行。若是您想在一個由 window.open 函數生成的新窗口中執行操做,那麼將焦點更換到新窗口。在彈出窗口中執行操做以後,焦點返回到主窗口。處理彈出窗口的過程定義在清單 12 中。


清單 12. 處理彈出窗口的樣例代碼

//wait for the popup window with timeout;
selenium.waitForPopUp(windowname, timeout); 
//select the pop up window
selenium.selectWindow(popupWindowIdentifier);
//perform action on popup window and close the window;
.... 
//return to the main window use 'null' 
selenium.selectWindow(null);

 

windowname 是調用 window.open 函數的第二個參數。上面提到的 popupwindowIdentifier 是一個窗口標識符,能夠是窗口 ID、窗口名稱、title=the title of the windowvar=javascript variable。若是彈出窗口的屬性未知,可是真的定義了,那麼使用 getAllWindowIds()getAllWindowNames()getAttributeFromAllWindows() 函數來檢索彈出窗口的屬性。

在最新版的 Selenium RC 1.0.1 中,Selenium 添加了像 selectPopUp(String)deselectPopUp() 這樣的方法,它們的功能在之前版本中由 selectWindow(String) 提供。


清單 13. 處理彈出窗口的彈出函數

//wait for the popup window with timeout;
selenium.waitForPopUp(「」, timeout); 
//same as selenium.selectWindow
selenium.selectPopUp(「」);
//perform action on popup window and close the window;
.... 
//same as selenium.selectWindow(null);
selenium.deselectPopUp();

 

清單 13 展現了處理彈出窗口最簡單的方式。您能夠保留 waitForPopUpselectPopUp 函數中的第一個參數爲空。若是同時彈出多個窗口,請指定窗口屬性。

如何處理上載/下載文件窗口

Selenium 使用 JavaScript 來模擬操做。所以,它不支持諸如上載窗口、下載窗口或身份認證窗口之類的瀏覽器元素。對於非主要窗口,配置瀏覽器跳過彈出窗口。


圖 7. 安全信息窗口
展現 Security Information 彈出窗口的屏幕快照,指出頁面包含安全的和不安全的條目

跳過圖 7 中安全信息窗口的解決方案是打開 Tools > Internet Options > Custom Level。而後啓用 Display mixed content

配置 Internet Explorer 跳過非主要窗口會減小或消除運行測試用例時沒必要要的處理。可是若是配置了 Firefox,那麼將它保存爲新的配置文件,並利用定製的配置文件啓動服務器。在關於測試 HTTPS 網站的一節中提到了這樣作的緣由。

對於上載/下載窗口,最好是處理而不是跳過它們。爲了不 Selenium 的侷限性,一種建議是使用 Java 機器人 AutoIt 來處理文件上載和下載問題。AutoIt 被設計來自動化 Window GUI 操做。它能夠認識大多數 Window GUI,提供不少 API,而且很容易轉換爲 .exe 文件,這樣的文件能夠直接運行或者在 Java 代碼中調用。清單 14 演示了處理文件上載的腳本。這些腳本的步驟是:

  1. 根據瀏覽器類型肯定上載窗口標題。
  2. 激活上載窗口。
  3. 將文件路徑放入編輯框中。
  4. 提交。


清單 14. 處理上載的 AutoIt 腳本

;first make sure the number of arguments passed into the scripts is more than 1 
If $CmdLine[0]<2 Then Exit EndIf
 handleUpload($CmdLine[1],$CmdLine[2])

;define a function to handle upload
 Func handleupload($browser, $uploadfile)
	 Dim $title                          ;declare a variable
            ;specify the upload window title according to the browser
            If $browser="IE" Then                  ; stands for IE;
 	      $title="Select file"
            Else                                 ; stands for Firefox
	       $title="File upload"
            EndIf
 
            if WinWait($title,"",4) Then ;wait for window with 
title attribute for 4 seconds;
                   WinActivate($title)                  ;active the window;
                   ControlSetText($title,"","Edit1",$uploadfile)   ;put the 
file path into the textfield  
                   ControlClick($title,"","Button2")                ;click the OK 
or Save button
            Else
	        Return False
            EndIf
 EndFunc 

 

在 Java 代碼中,定義一個函數來執行 AutoIt 編寫的 .exe 文件,並在單擊 browse 以後調用該函數。


清單 15. 執行 AutoIt 編寫的 .exe 文件

public void handleUpload(String browser, String filepath) {
	String execute_file = "D:\\scripts\\upload.exe";
	String cmd = "\"" + execute_file + "\"" + " " + "\"" + browser + "\""
				+ " " + "\"" + filepath + "\""; //with arguments
	try {
		Process p = Runtime.getRuntime().exec(cmd);
		p.waitFor(); //wait for the upload.exe to complete
	} catch (Exception e) {
		e.printStackTrace();
	}
}

 

清單 16 是處理 Internet Explorer 中下載窗口的 AutoIt 腳本。Internet Explorer 和 Firefox 中的下載腳本各不相同。


清單 16. 處理 Internet Explorer 中下載的 AutoIt 腳本

If $CmdLine[0]<1 Then Exit EndIf
handleDownload($CmdLine[1])
Func handleDownload($SaveAsFileName)
Dim $download_title="File Download" 
If WinWait($download_title,"",4) Then
    WinActivate($download_title)
    Sleep (1000)
    ControlClick($download_title,"","Button2","")
    Dim $save_title="Save As"
    WinWaitActive($save_title,"",4)
    ControlSetText($save_title,"","Edit1", $saveAsFileName)
    Sleep(1000)
    if FileExists ($SaveAsFileName) Then
	FileDelete($SaveAsFileName)
	EndIf
    ControlClick($save_title, "","Button2","")
    Return TestFileExists($SaveAsFileName)
Else
    Return False
EndIf
EndFunc

 

AutoIt 腳本很容易編寫,可是依賴於瀏覽器類型和版本,由於不一樣的瀏覽器和版本中,窗口標題和窗口控件類是不相同的。

如何驗證警告/確認/提示信息

對於由 window.alert() 生成的警告對話框,使用 selenium.getAlert() 來檢索前一操做期間生成的 JavaScript 警告的消息。若是沒有警告,該函數將會失敗。獲得一個警告與手動單擊 OK 的結果相同。

對於由 window.confirmation() 生成的確認對話框,使用 selenium.getConfirmation() 來檢索前一操做期間生成的 JavaScript 確認對話框的消息。默認狀況下,該函數會返回 true,與手動單擊 OK 的結果相同。這能夠經過優先執行 chooseCancelOnNextConfirmation 命令來改變。

對於由 window.prompt() 生成的提示對話框,使用 selenium.getPromt() 來檢索前一操做期間生成的 JavaScript 問題提示對話框的消息。提示的成功處理須要優先執行 answerOnNextPrompt 命令。

JavaScript 警告在 Selenium 中不會彈出爲可見的對話框。處理這些彈出對話框失敗會致使異常,指出沒有未預料到的警告。這會讓測試用例失敗。

相關文章
相關標籤/搜索