在軟件生命周期各個(gè)階段都逐漸開(kāi)始重視交付速度的情況下,全球化測(cè)試同樣也面臨了敏捷的挑戰(zhàn)。因此自動(dòng)化測(cè)試也開(kāi)始在全球化測(cè)試領(lǐng)域變得流行起來(lái),但是由于受限于翻譯驗(yàn)證性測(cè)試中"一次編寫(xiě),多個(gè)語(yǔ)言環(huán)境下運(yùn)行"的特點(diǎn),在利用 Selenium 進(jìn)行 Web 自動(dòng)化測(cè)試時(shí)對(duì)元素的一致定位成了編寫(xiě)自動(dòng)化腳本的瓶頸。本文將針對(duì)現(xiàn)階段遇到的問(wèn)題結(jié)合實(shí)例詳細(xì)闡述在利用 Selenium 對(duì) Web 應(yīng)用進(jìn)行自動(dòng)化測(cè)試時(shí)定位元素的方法,并針對(duì)全球化測(cè)試中遇到的難點(diǎn)給予重點(diǎn)解答。
翻譯驗(yàn)證性測(cè)試中定位 Web 元素遇到的挑戰(zhàn)
翻譯驗(yàn)證性測(cè)試是全球化測(cè)試中的一部分,旨在驗(yàn)證軟件用戶界面中需要翻譯的字符串是否已經(jīng)正確翻譯。為了提高效率,目前一般采用先由熟悉產(chǎn)品的測(cè)試支持工程師書(shū)寫(xiě)測(cè)試用例,再由熟悉各國(guó)語(yǔ)言的測(cè)試人員執(zhí)行用例或者先由測(cè)試支持工程師將復(fù)雜用例的執(zhí)行結(jié)果在各個(gè)語(yǔ)言環(huán)境下截圖,然后再發(fā)送給測(cè)試人員進(jìn)行驗(yàn)證兩種模式。目前隨著持續(xù)交付模式的出現(xiàn),無(wú)論是測(cè)試人員多語(yǔ)言環(huán)境下重復(fù)執(zhí)行用例還是測(cè)試支持工程師多語(yǔ)言環(huán)境下手動(dòng)截圖都難以滿足持續(xù)交付對(duì)速度的要求,因此測(cè)試支持工程師編寫(xiě)自動(dòng)化腳本完成多語(yǔ)言環(huán)境下的自動(dòng)截圖變成了提高效率的必然選擇。
在傳統(tǒng)的 Web 自動(dòng)化測(cè)試應(yīng)用場(chǎng)景中,由于程序編碼的不規(guī)范,元素通常很難直接通過(guò)靜態(tài) ID 或 name 定位,幸好有 CSS 選擇器和 XPath 定位為我們提供了新的可能。然而由于 DHTML 和 Ajax 的盛行,新的挑戰(zhàn)又?jǐn)[在了測(cè)試人員面前,由 Dojo 等客戶端腳本生成的 DOM 結(jié)構(gòu)異常復(fù)雜:層次繁多且一個(gè) DOM 樹(shù)上可能存在多個(gè)頁(yè)面的 DOM 子節(jié)點(diǎn),而且其中元素的 ID 是動(dòng)態(tài)的(該 ID 一般由一個(gè)前綴和一個(gè)動(dòng)態(tài)的數(shù)字組成,前綴表明了元素對(duì)應(yīng)的部件類型,數(shù)字則由運(yùn)行時(shí)該小部件在 DOM 樹(shù)上的位置確定)。這導(dǎo)致了有些元素甚至需要依靠 CSS 偽類再運(yùn)用組合選擇器才能精確定位的到。而對(duì)于在翻譯驗(yàn)證性測(cè)試中的自動(dòng)化,這種問(wèn)題尤其突出,由于翻譯驗(yàn)證性測(cè)試中的自動(dòng)化腳本“一次編寫(xiě),多個(gè)語(yǔ)言環(huán)境下”運(yùn)行的要求,元素定位的后“救命稻草”-CSS 偽類中的內(nèi)文本匹配也無(wú)法開(kāi)箱即用了。
下面筆者將通過(guò)實(shí)例詳細(xì)闡述元素定位的方法,以期讀者能靈活運(yùn)用以應(yīng)對(duì)上述的各種挑戰(zhàn)。
Selenium IDE 與 WebDriver 定位元素概覽
Selenium 是一款強(qiáng)大的瀏覽器自動(dòng)化工具,利用它可以實(shí)現(xiàn) Web 界面測(cè)試的自動(dòng)化。根據(jù)實(shí)現(xiàn)原理和使用方式的不同,其又分為 Selenium IDE 和 WebDriver,前者以瀏覽器插件的方式賦予用戶簡(jiǎn)單快速地創(chuàng)建自動(dòng)化腳本的能力,后者則通過(guò) API 庫(kù)的形式向用戶提供更加靈活和健壯的 Web 自動(dòng)化能力。
Selenium IDE 在其命令中采用 locatorType=location 的格式進(jìn)行定位,該方法將定位到條件匹配的第一個(gè)元素,一般情況下 locatorType 可以省略;WebDriver 利用 findElement(By.locatorType("value") 或 findElements(By.locatorType("value") 函數(shù)查找元素,前者將返回一個(gè)的元素,后者將返回一個(gè)元素列表。具體的定位由 By.locatorType("value") 實(shí)現(xiàn)。
除去定位使用的方法而言,二者本質(zhì)上都是通過(guò) locatorType 進(jìn)行定位的,常用的 locatorType 包括 id,name,link text,dom/JavaScript,xpath,css 等,示例見(jiàn)清單 2(行末括號(hào)中的數(shù)字顯示當(dāng)前行定位器將定位到清單 1 HTML 文檔中的第幾行元素):
清單 1. HTML 示例 1
(01)<html>
(02) <body>
(03) <form id="loginForm" name="loginFrom">
(04) <input class="required" name="username" type="text" />
(05) <input class="required passfield" name="password" type="password" />
(06) <input name="continue" type="submit" value="Login" />
(07) <input name="continue" type="button" value="Clear" />
(08) </form>
(09) <p>Are you sure you want to do this?</p>
(10) <a href="continue.html">Continue</a>
(11) <a href="cancel.html">Cancel</a>
(12)</body>
(13)<html>
清單 2. Selenium 和 WebDriver 中通用的定位方式
//by ID
id=loginForm(03)//in IDE
WebElement element = driver.findElement(By.id("loginForm"));(03)//in WebDriver
//by Name
name=continue type=button(07)//in IDE
WebElement element = driver.findElement(By.name("loginForm"));(03)//in WebDriver
//by link text
link=Continue(10)//in IDE
WebElement element = driver.findElement(By.linkText("Continue"));(10)//in WebDriver
//by DOM or JavaScript
dom=document.forms[0].elements['username'](04)//use DOM in IDE
WebElement element = (WebElement) ((JavascriptExecutor)driver).
executeScript("return $('.required')[0]"); (04)//use JQuery in WebDriver
//by XPath
//form[@id='loginForm']/input[1](04)//by IDE
WebElement element = driver.findElement(By.xpath("//input[@name='username']"));(04)//by WebDriver
//by CSS
css=#loginForm input[type="password"](05)//by IDE
WebElement e = driver.findElement(By.cssSelector("input.passfield")(05)//by WebDriver
通過(guò) ID 和 name 定位是高效也是的定位方式,不過(guò)由于 name 不一定,在定位時(shí)匹配條件的元素可能有多個(gè),因此這種情況下只會(huì)定位到匹配條件的第一個(gè)元素。針對(duì)多個(gè)元素具有相同 name(或鏈接文本)屬性的情況還需額外增加其他的過(guò)濾器才能進(jìn)行精確定位,如清單 2 中 IDE 利用 name 進(jìn)行定位的示例。
DOM 代表了整個(gè) HTML 文檔的結(jié)構(gòu),使用 JavaScript 可以訪問(wèn) DOM 中的節(jié)點(diǎn)。Selenium IDE 基于 DOM 結(jié)構(gòu)可以使用 JavaScript 的點(diǎn)操作符進(jìn)行層次定位以簡(jiǎn)化定位操作,由于只有 DOM 定位器以“document”開(kāi)頭,因此“dom=”也可以省略;此外在 WebDriver 中甚至可以通過(guò)執(zhí)行任意的返回值為 DOM 對(duì)象的 JavaScript 語(yǔ)句來(lái)查找元素,如清單 2 中 WebDriver 使用 JQuery(一種 JavaScript 框架)的元素查找函數(shù)$進(jìn)行定位。
XPath 初是用來(lái)在 XML 文檔中定位 DOM 節(jié)點(diǎn)的語(yǔ)言,由于 HTML 也可以算作 XML 的一種實(shí)現(xiàn),所以 Selenium 也可以利用 XPath 這一強(qiáng)大的語(yǔ)言來(lái)定位 Web 元素。XPath 在傳統(tǒng)屬性定位之外擴(kuò)展了諸如“定位第三個(gè)多選框”等定位能力,以便應(yīng)對(duì)沒(méi)有 ID 或 name 屬性的情況。利用 Xpath 可以通過(guò)路徑,或者相對(duì)于一個(gè)可精確定位的元素的相對(duì)路徑來(lái)定位。為了保證定位的健壯性,推薦使用相對(duì)路徑和基于位置關(guān)系的定位。同樣由于只有 XPath 定位器以“//”開(kāi)頭,所以“xpath=”也可以省略。
CSS (Cascading Style Sheets) 是一種用于渲染 HTML 或者 XML 文檔的語(yǔ)言,CSS 利用其選擇器可以將樣式屬性綁定到文檔中的指定元素,即前端開(kāi)發(fā)人員可以利用 CSS 設(shè)定頁(yè)面上每一個(gè)元素的樣式。所以理論上說(shuō)無(wú)論一個(gè)元素定位有多復(fù)雜,既然開(kāi)發(fā)人員能夠定位到并設(shè)置樣式,那么測(cè)試人員同樣應(yīng)該也能定位繼而操作該元素。這也正是 Selenium 官方極力推薦使用 CSS 定位,而不是 XPath 定位的主要原因。CSS 定位被推崇的另一個(gè)原因是不同的瀏覽器 XPath 引擎不同甚至沒(méi)有自己的 Xpath 引擎,這導(dǎo)致了 XPath 定位速度較慢,而采用 CSS 定位往往能用更簡(jiǎn)潔的語(yǔ)法快速定位到復(fù)雜的元素。因此后文將詳細(xì)介紹 CSS 定位器的使用方法。
除了以上通用的定位方式之外,在 Selenium IDE 中還可通過(guò) identifier 進(jìn)行定位,這是通用也是默認(rèn)的定位方式,其定位時(shí)首先將 identifier 的值視為 ID 繼而查找匹配元素,沒(méi)有匹配項(xiàng)之后再把其看作 name 進(jìn)行查找,直到找到第一個(gè)匹配的元素為止。由于其是默認(rèn)的定位方式,因此“identifier=”通常也會(huì)省略。對(duì)于 WebDriver 而言,特有的定位方式更多。首先它可以通過(guò)鏈接文本進(jìn)行部分匹配,如清單 3 所示;然后它還可以通過(guò)標(biāo)簽名或者 CSS 類名的方式進(jìn)行定位,利用 findElement 的話這兩種方式均是定位到第一個(gè)匹配條件的元素,利用 findElements 則可獲得一個(gè)所有滿足條件的元素列表,如清單 3 所示。