圖 3. 修改后的在 Dojo 組合框中進行選擇的 IDE 腳本
selenium.waitForCondition("selenium.isElementPresent(\"offeringType_popup2\")", "2000");
圖 4. 日期選擇器
如本例所示,Dojo 應用程序不能通過簡單的 IDE 記錄進行測試。這些腳本有可能不能通過測試。腳本中有一些丟失的操作,或者操作并不真正工作。腳本應該調(diào)整成能夠在 IDE 和 RC 中順利地執(zhí)行。對于復雜的 Dojo 小部件,一種可能的解決方案是使用 runScript(String) 函數(shù),因為 Selenium 對 JavaScript 提供很好的支持。清單 5 提供一個 JavaScript 語句來模擬組合框選擇。
諸如 Ant 這樣的集成工具可以方便地構建 Selenium 測試和順暢地運行測試用例,無需單獨啟動 Selenium 服務器。如果 Selenium 測試由 TestNG 驅(qū)動,那么定義清單 6 所示 TestNG Ant 任務。清單 6 中假設 classpath 是 TestNG.jar 文件的文件路徑。
<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 已經(jīng)成功啟動。在清單 7 中,它最多等待兩分鐘,并且每 100 毫秒在本地主機上檢查一次 Selenium 服務器,以提供完整的 URL。
start-server 任務的詳細內(nèi)容定義在清單 8 中。Firefox profile 模板位置和其他參數(shù)可以指定在標記 <arg> 中。
清單 8. 詳細的啟動服務器的 Ant 任務
<target name="start-server">
<java jar="lib/selenium-server.jar" fork="true">
<arg line="-firefoxProfileTemplate ${selenium}/profile/" />
</java>
</target>
runTestNG 任務的詳細內(nèi)容定義在清單 9 中。testng 任務的常用屬性包括 outputDir 和 xmlfileset。屬性 outputDir 用于設置輸出報告位置。屬性 xmlfileset 用于包含啟動 XML 文件。更多選項請參考 TestNG 正式網(wǎng)站。
清單 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 任務的詳細內(nèi)容定義在清單 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 網(wǎng)站
隨著互聯(lián)網(wǎng)日益強調(diào)信息安全,越來越多的 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 網(wǎng)站時出現(xiàn)一個如下所示的安全警告,那么單擊 View Certificate 并安裝 HTTPS 網(wǎng)站的證書。如果繼續(xù)彈出警告,那么考慮在 IE 中進行配置。打開 Tool > Internet Options > Advanced,并取消選擇 security 分類下的 Warn about invalid site certificates 和 Check for publisher's certificate revocation。
圖 5. 測試 HTTPS 網(wǎng)站時的安全警告
創(chuàng)建新的 Firefox 配置文件
對于 Firefox,遵循以下步驟創(chuàng)建定制的配置文件,然后重啟服務器:
關閉任何正在運行的 Firefox 實例。
利用配置文件管理器 firefox -ProfileManager 啟動 Firefox。
創(chuàng)建一個新的配置文件。出現(xiàn)提示時,為配置文件選擇一個目錄。將它放在項目文件夾里面。
選擇配置文件并運行 Firefox。
利用您將用于測試的自簽名證書導航到 HTTPS URL。 出現(xiàn)提示時接受證書。這將在配置文件中創(chuàng)建一個異常。
關閉瀏覽器。
轉(zhuǎn)到 Firefox 配置文件目錄。
刪除該目錄中除 cert_override.txt 和 cert8.db 文件之外的任何東西。
默認情況下,Selenium 將在啟動 Firefox 的實例時創(chuàng)建一個新的配置文件。當您利用參數(shù) -firefoxProfileTemplate /path/to/profile/dir 啟動服務器時,Selenium 將使用一個部分配置文件(帶有證書異常)作為創(chuàng)建新配置文件的基礎。這將提供證書異常,而避免了使用整個配置文件帶來額外的混亂。注意一下在 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 起,它們已經(jīng)穩(wěn)定成 *firefox 和 *iexplore 運行模式。請謹慎地根據(jù)所使用的 Selenium 版本而使用運行模式。
如何高效地認識不帶 ID 屬性的 web 元素
使用一個有含義的 ID 或名稱是一種高效且方便的定位元素的方式。它也可以改善測試用例的可讀性。但是為了每個元素具有一個有含義的、惟一的 ID(尤其是動態(tài)元素),Selenium 提供多種策略來認識元素,比如說 Xpath、DOM 和 CSS。
下面是一個樣例,使用三種策略來定位圖 6 中提供的動態(tài)表格中的一個元素。HTML 代碼在清單 11 中。
圖 6. 動態(tài)表格樣例
清單 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 表達式
表 1 展示了定位元素的 Xpath 表達式。在 Firebug 的幫助下,Xpath 可以定位元素和復制的元素。在元素沒有 ID 和名稱時,Selenium IDE 將會采用 Xpath。盡管 Xpath 利用已經(jīng)錄的腳本,有助于保持一致性,但是它高度依賴于 web 頁面的結(jié)構。這使得測試用例可讀性差,增加了維護難度。此外,在 Internet Explorer 7 和 Internet Explorer 8 中運行具有多個復雜 Xpath 表達式的測試用例可能會太慢了。在這種情況下,將 Xpath 更換為 DOM,后者是另一種高效的定位策略。
DOM 是 Document Object Model(文檔對象模型)的縮寫。Selenium 允許您利用 JavaScript 遍歷 HTML DOM。Java 的靈活性允許在 DOM 表達式中有多個語句,用分號隔開,以及在語句中定義函數(shù)。
表 2. 定位元素的 DOM 表達式
表 2 展示了定位元素的 DOM 表達式。DOM 定位器在 Firefox 和 Internet Explorer 中也有很好的性能。組織 DOM 表達式需要一些 JavaScript 知識。有時,DOM 表達式對于復雜的元素來說太長了,難以看懂(參見表 2 中提到的 Test 1 的編輯鏈接的表達式)。
CSS 定位器用于利用 CSS 選擇器選擇元素。當 HTML 代碼具有良好的樣式時,可以高效地利用 CSS 定位器。樣例表達式展示在表 3 中。
表 3. 定位元素的 CSS 表達式
一般來說,選用熟悉的定位器表達式,并在腳本結(jié)構中保持一致。如果有多種表達式可執(zhí)行,那么使用最高效的方式在 web 頁面中定位元素。
如何處理彈出窗口
一般來說,操作都是在由 Selenium 啟動的主窗口中執(zhí)行。如果您想在一個由 window.open 函數(shù)生成的新窗口中執(zhí)行操作,那么將焦點更換到新窗口。在彈出窗口中執(zhí)行操作之后,焦點返回到主窗口。處理彈出窗口的過程定義在清單 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 是調(diào)用 window.open 函數(shù)的第二個參數(shù)。上面提到的 popupwindowIdentifier 是一個窗口標識符,可以是窗口 ID、窗口名稱、title=the title of the window 或 var=javascript variable。如果彈出窗口的屬性未知,但是真的定義了,那么使用 getAllWindowIds()、getAllWindowNames() 或 getAttributeFromAllWindows() 函數(shù)來檢索彈出窗口的屬性。
在最新版的 Selenium RC 1.0.1 中,Selenium 添加了像 selectPopUp(String) 和 deselectPopUp() 這樣的方法,它們的功能在以前版本中由 selectWindow(String) 提供。
清單 13. 處理彈出窗口的彈出函數(shù)
//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 展示了處理彈出窗口最簡單的方式。您可以保留 waitForPopUp 和 selectPopUp 函數(shù)中的第一個參數(shù)為空。如果同時彈出多個窗口,請指定窗口屬性。
如何處理上載/下載文件窗口
Selenium 使用 JavaScript 來模擬操作。因此,它不支持諸如上載窗口、下載窗口或身份認證窗口之類的瀏覽器元素。對于非主要窗口,配置瀏覽器跳過彈出窗口。
圖 7. 安全信息窗口
跳過圖 7 中安全信息窗口的解決方案是打開 Tools > Internet Options > Custom Level。然后啟用 Display mixed content。
配置 Internet Explorer 跳過非主要窗口會減少或消除運行測試用例時不必要的處理。但是如果配置了 Firefox,那么將它保存為新的配置文件,并利用定制的配置文件啟動服務器。在關于測試 HTTPS 網(wǎng)站的一節(jié)中提到了這樣做的原因。
對于上載/下載窗口,最好是處理而不是跳過它們。為了避免 Selenium 的局限性,一種建議是使用 Java 機器人 AutoIt 來處理文件上載和下載問題。AutoIt 被設計來自動化 Window GUI 操作。它可以認識大多數(shù) Window GUI,提供很多 API,并且很容易轉(zhuǎn)換為 .exe 文件,這樣的文件可以直接運行或者在 Java 代碼中調(diào)用。清單 14 演示了處理文件上載的腳本。這些腳本的步驟是:
根據(jù)瀏覽器類型確定上載窗口標題。
激活上載窗口。
將文件路徑放入編輯框中。
提交。
清單 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 代碼中,定義一個函數(shù)來執(zhí)行 AutoIt 編寫的 .exe 文件,并在單擊 browse 之后調(diào)用該函數(shù)。
清單 15. 執(zhí)行 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 警告的消息。如果沒有警告,該函數(shù)將會失敗。得到一個警告與手動單擊 OK 的結(jié)果相同。
對于由 window.confirmation() 生成的確認對話框,使用 selenium.getConfirmation() 來檢索前一操作期間生成的 JavaScript 確認對話框的消息。默認情況下,該函數(shù)會返回 true,與手動單擊 OK 的結(jié)果相同。這可以通過優(yōu)先執(zhí)行 chooseCancelOnNextConfirmation 命令來改變。
對于由 window.prompt() 生成的提示對話框,使用 selenium.getPromt() 來檢索前一操作期間生成的 JavaScript 問題提示對話框的消息。提示的成功處理需要優(yōu)先執(zhí)行 answerOnNextPrompt 命令。
JavaScript 警告在 Selenium 中不會彈出為可見的對話框。處理這些彈出對話框失敗會導致異常,指出沒有未預料到的警告。這會讓測試用例失敗。