善用Selenium擴充,測試更加得心應手

講到網頁自動測試,一哥地位非 Selenium 莫屬(參考)。雖然 Selenium IDE 支援錄製網頁操作產生測試腳本,但錄製產生的指令常依賴元素的位置順序定位,配置稍有更動立刻破功。依實務經驗,開發者依據設計邏輯手工撰寫還是較可靠的作法,測試指令也較簡潔有效率。Selenium 本身提供好幾種定位器,包含:ID、Name、DOM、XPATH、CSS Selector…等。習慣 jQuery 再回頭使用這些彈性受限的定位器,每每遇到複雜情境,都會先想 jQuery 如何操作,再設法對應成 CSS Selector,但三不五時就會超出 CSS 能力範圍(例如::contains()、:has(),或是結合 closest()、parent() ),心中滿是恨鐵不成鋼的怨氣。

既然 jQuery 好用,我測試的網頁也多半已載入 jQuery,為什麼寫測試時必須將就這堆能力受限的內建定位器呢?最後,我找到一個解法,為 Selenium 寫擴充函式直接支援 jQuery!

我寫了一個user-extensions.js,為 Selenium 類別加入幾個新函式:

  • locateElementByJq: 所有適用 css=… 選擇器的場合,都可以寫成  jq=… 使用 jQuery 選擇器
  • getJqText:支援 verifyJqText/waitForJqText,傳入 jQuery 選擇器取回 .text()
  • getJqVal:支援 verifyJqVal/waitForJqVal,傳入 jQuery 選擇器取回 .val()
  • getJqHtml:支援 verifyJqHtml/waitForJqHtml,傳入 jQuery 選擇器取回 .val()
  • doExecute:Selenium 雖然有 runScript,但執行時 this 指向 Selenium 物件,如要存取 DOM 必須寫 window.document.* 有點囉嗉。改良版的 execute 支援直接輸入 JavaScript,以 window.eval() 執行,就跟在 F12 主控台下指令一樣方便。因此,execute 是為我寫測試最慣用的兵器。
  • getExecute:沿用 execute 概念,可執行複雜 JavaScript 指令自網頁取值,可配合 verifyForExecute、waitForExecute 使用,威力強大!(例如:取得元素內容進行 Regular Expression 比對、檢查元素個數介於 2 到 4 之間… 這類內建指令不易實現的運算比對)

user-extensions.js 的內容如下:

//http://docs.seleniumhq.org/docs/08_user_extensions.jsp
Selenium.prototype.doExecute = function(script) {
    this.browserbot.getCurrentWindow().eval(script);
};
Selenium.prototype.getExecute = function(script) {
    return this.browserbot.getCurrentWindow().eval(script);
};
Selenium.prototype.getJqMethod = function(selector, method) {
    return this.getExecute('$("' + selector + '").' + method + '();');
};
Selenium.prototype.getJqText = function(selector) {
    return this.getJqMethod(selector, "text");
};
Selenium.prototype.getJqHtml = function(selector) {
    return this.getJqMethod(selector, "html");
};
Selenium.prototype.getJqVal = function(selector) {
    return this.getJqMethod(selector, "val");
};
PageBot.prototype.locateElementByJq = function(selector, inDocument) {
    // FF/Chrome/IE9+: defaultView, OldIE: parentWindow
    return (inDocument.defaultView || inDocument.parentWindow)
            .eval("jQuery('" + selector.replace(/'/g, "\\'") + "')[0];");
};

要使用它,只需開啟 Selenium IDE 選項設定,加入 user-extensions.js 路徑。血清注射完成,美國隊長要現身了!

用一個簡單網頁示範:

<!DOCTYPE html>
 
<html>
    <body>
        <div>
            <input type="text" value="Darkthread" />
            <span class='name'>Jeffrey</span>
        </div>
        <div>
            <input type="button" value="Hide" />
            <span>Test</span>
        </div>
        <div class="last">
            <input type="text" value="Selenium" disabled />
            <span style="display:none">Selenium IDE</span>
        </div>
        <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.9.1.js"></script>
        <script>
            $(":button").click(function() {
                $(".name").hide(3000);
            });
        </script>
    </body>
</html>

如以下圖示,展示使用 jq=div:has(:text) 配合 verifyElementPresent 可以做到 CSS 不支援的 :has() 選擇器;verifyExecute 時應用 JavaScript .match() 做 Regular Expression 比對;另外還展示用 execute 執行 JavaScript 直接對 DOM 動手動腳。

能使用 jQuery 選擇器,又可直接用 JavaScript 操作網頁或進行運算,就能輕鬆在 Selenium 測試案例加入各種自訂邏輯,寫起測試案例再也不會被綁手綁腳囉!

歡迎推文分享:
Published 17 September 2014 07:46 AM 由 Jeffrey
Filed under:
Views: 7,353



意見

# lrd@hust.edu.tw said on 07 November, 2017 09:29 PM

您好,

因您文章受用良深,請教您一問題如附檔視訊,

drive.google.com/.../view

環境為FF&SideeX is an extended version of Selenium IDE,

CLICK指令可點到輸入欄位之ID,可是相同欄位相同ID,TYPE指令卻是未見任何動作,也就是未自動打字,WHY?

麻煩您了

lrd@hust.edu.tw

# Jeffrey said on 08 November, 2017 03:43 AM

to Ird, 只有某個欄位有問題還是全面失效? 改用sendKeys/typeKeys結果會不同嗎?

你的看法呢?

(必要的) 
(必要的) 
(選擇性的)
(必要的) 
(提醒: 因快取機制,您的留言幾分鐘後才會顯示在網站,請耐心稍候)

5 + 3 =

搜尋

Go

<September 2014>
SunMonTueWedThuFriSat
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011
 
RSS
創用 CC 授權條款
【廣告】
twMVC
最新回應

Tags 分類檢視
關於作者

一個醉心技術又酷愛分享的Coding魔人,十年的IT職場生涯,寫過系統、管過專案, 也帶過團隊,最後還是無怨無悔地選擇了技術鑽研這條路,近年來則以做一個"有為的中年人"自許。

文章典藏
其他功能

這個部落格


Syndication