[譯] 用 CSS 選擇器和自定義屬性來升級你的專案

Colafornia發表於2017-12-22

用 CSS 選擇器和自定義屬性來升級你的專案

這篇文章原文刊登在 TestProject。感謝你們的支援,讓 SitePoint 成為可能。

Selenium WebDriver 的元素選擇器是 自動化測試框架 中所提及的核心元件中的一種,同時也是與 web 應用進行互動的關鍵。在對 自動化元素選擇器 的回顧中, 我們討論了很多不同的選擇器應用策略,探究其功能,權衡優缺點,最終我們推薦 最佳的選擇器應用策略 —— 帶有自定義屬性的 CSS 選擇器。

Selenium 的元素選擇器

選擇最好的 元素選擇器 策略是成功的關鍵,也減輕了自動化工作的維護壓力。因此,做出選擇的時候應該從使用難度,多功能性,是否具有線上支援,文件豐富程度以及效能等多方面進行考慮。前期的充分考慮是有回報的,自動化工作會更容易維護。

就像從技術方面考慮元素選擇器一樣,也要考慮到團隊文化。在自動化工作中採用元素選擇器時,在開發者與 QA 之間成熟的合作文化可以解鎖更高成就,取得更好的效果。夯實軟體開發週期中其它方面的合作基礎不僅對自動化工作有益,更是對團隊有益。

所有的程式碼示例都是由 PythonSelenium WebDriver 中的命令編寫而成,但也普遍適用於其它程式語言和框架。

HTML 程式碼示例:

在每一段的示例中,都是使用以下導航選單的 HTML 片段程式碼:

<div id="main-menu">
  <div class="menu"><a href="/home">Home</a></div>
  <div class="menu"><a href="/shop">Shop</a>
    <div class="submenu">
      <a href="/shop/gizmo">Gizmo</a>
      <a href="/shop/widget">Widget</a>
      <a href="/shop/sprocket">Sprocket</a>
    </div>
  </div>
</div>
複製程式碼

糟糕的選擇器: 標籤名,連結文字,部分連結文字和 name 屬性選擇器

關於這部分內容不需要花太多時間來講,因為這些選擇器的使用場景都很有限。在整個自動化框架中廣泛使用這些選擇器不是一個好選擇。它們所完成的需求完全可以通過其它元素選擇器策略輕鬆實現。只有在特定需求中需要去處理特殊案例的時候才使用這幾種選擇器。即使如此,大多數特殊場景並沒有特殊到非要使用這幾種選擇器才能解決。你可以在沒有其他選擇器選項可用(例如自定義標籤或 id)的情況下使用。

舉個栗子:

使用標籤名稱選擇器,會選擇到非常多的匹配到標籤名稱的元素。它的用途非常有限,只能作為在需要選擇大量相同型別的元素的唯一情況下的解決方案。下面這個例子會返回示例 HTML 程式碼中全部 4 個 div 元素。

driver.find_elements(By.TAG_NAME, "div")
複製程式碼

也可以像下面的例子這樣通過連結來選擇。如你所見,這樣只能定位到錨點標籤而且只能定位這些錨點標籤的文字:

driver.find_elements(By.LINK_TEXT, "Home")
driver.find_elements(By.PARTIAL_LINK_TEXT, "Sprock")
複製程式碼

最後,也可以通過 name 屬性來選擇元素,但是在 HTML 程式碼示例中可以看出,那些標籤是沒有 name 屬性的。這在絕大多數應用中都是一個常見問題,因為給每個 HTML 屬性中新增一個 name 屬性不是常規的程式碼實踐。假如主選單元素像下面一樣有一個 name 屬性:

<div id="main-menu" name="menu"></div>
複製程式碼

可以像這樣匹配到這個元素:

driver.find_elements(By.NAME, "menu")
複製程式碼

如你所見,以上這些元素選擇策略的使用場景都很有限。下面的方法都會更好一些,它們更靈活多變。

總結: 標籤名,連結文字,部分連結文字和 name 屬性選擇器

優點 缺點
使用簡單 不夠靈活
使用場景極其有限
在某些場景甚至可能用不了

還不錯的選擇器: XPath

XPath 是一種靈活多變的選擇器策略。這是我個人很喜歡的。XPath 可以選擇頁面中的任意元素,無論它有沒有 class 和 id (雖然沒有 class 和 id 的話很難維護)。該選項非常靈活有用,因為你可以選擇 父元素。XPath也有許多內建的功能,可以讓你自定義元素選擇。

但是,多功能性也帶來了複雜性。鑑於 XPath 可以做這麼多事,相比於其它選擇器,它的學習曲線也更陡峭。這一不足是可以被它非常讚的線上文件抵消的。在 W3Schools.com 上找到的 XPath 入門指南 是一個很不錯的資源。

還應該指出,使用 XPath 的時候有一件事需要進行權衡。雖然可以通過 XPath 選擇父元素並使用一系列內建函式,但是 XPath 在 IE 瀏覽器的表現不佳。在選擇元素選擇器策略時,應該考慮這個問題。如果你有選擇父元素的需要的話,要考慮它對 IE 上進行的 跨瀏覽器 測試的影響。本質上,在 IE 中執行自動化測試的耗時更長。如果你的使用者群體的 IE 使用率不高的話,考慮到在 IE 上跑測試的時候更少,XPath 依然是一個好選擇。如果你的使用者基本上都是 IE 重度使用者的話,XPath 就只能作為沒有其它更好方式時的備胎選擇了。

舉個栗子:

如果你有需求要選擇父元素,那就必須採用 XPath。下面是做法,依然使用我們的示例,假設你要定位一個基於錨點元素的主選單元素的父元素:

driver.find_elements(By.XPATH, "//a[id=menu]/../")
複製程式碼

這個元素選擇器會定位到第一個 id 等於 "menu" 的錨點標籤,然後通過 “/../” 定位到它的父元素。最終結果就是你會定位到主選單元素。

總結: XPath

優點 缺點
可以定位到父元素 IE 上表現欠佳
非常靈活 陡峭的學習曲線
非常多的線上支援

超級棒的元素選擇器: ID 和 Class

ID 和 Class 元素選擇器在自動化中是兩個不同的選項,會在應用程式中執行不同的功能。然而作為自動化工作的選擇器策略,這兩種選擇器的區別很小,我們沒必要將它們分開考慮。在應用程式中,UI 介面開發者可以操作和給定義了 "id" 和 "class" 屬性的元素設定樣式。對於自動化工作來說,我們使用它們來針對特定元素進行互動。

使用 ID 和 Class 原則器的一大好處是它們受應用程式結構變化的影響最小。假設,你要建立一個鏈式地依賴於一些元素和 子元素 的 XPath 或 CSS 選擇器,如果此時有一個功能需要增加一些新元素從而中斷了這個鏈條,會發生什麼?使用 ID 和 Class 元素選擇器,您可以定位特定的元素,而不是依賴頁面結構。同時也沒有過於寬鬆易變。應該通過給特定元素的位置建立測試用例來自動檢測改動。改動不應該毀壞你的整個自動化套件。但是,如果開發者直接對自動化中使用的 ID 或 Class 進行更改的話,還是會影響到你的測試。

又或者如果 HTML 標籤沒有自動化程式中可使用的 ID 和 Class 屬性的話,這種策略就無法使用。如果 HTML 標籤沒有自動化程式中可使用的 ID 和 Class 屬性的話,這種方法就很難使用。

舉個栗子:

在示例中,如果我們想選擇到頂級的選單元素,那應該是這樣的:

driver.find_elements(By.ID, "main-menu")
複製程式碼

如果要選擇第一個選單項,則是這樣:

driver.find_elements(By.CLASS_NAME, "menu")
複製程式碼

總結: ID 和 Class 選擇器

優點 缺點
易於維護 開發人員可能會直接修改它們,自動化工作就無法進行了
學習難度低
受頁面結構的影響最小

最佳的元素選擇器: 具有自定義屬性的 CSS 選擇器

如果你們的 QA 團隊與開發部門合作良好的話,你們很有可能會選擇這種最佳實踐方法應用到自動化工作中。使用自定義屬性和 CSS 選擇器來定位元素對於 QA 團隊和整個組織來說都有很多好處。對於 QA 團隊來說,這可以讓自動化工程師直接定位到特定元素,無需建立複雜的元素原則器。但是,這需要在應用程式中新增自動化團隊所需的屬性。為了充分發揮最佳實踐的優勢,開發部門和 QA 團隊應共同實施這一策略。

我想簡短地提示一下,CSS 選擇器方法並不依賴於自定義屬性。CSS 選擇器可以像 XPath 一樣定位到 HTML 文件流中的任意標籤和屬性。

現在我們來看這個方法需要我們做什麼。為了能最好地執行這一策略,你們的自動化團隊瞭解自己在自動化工作中想要定位什麼。在與開發人員的合作中,最有可能是與前端工程師的合作中,QA 團隊需要制定一個自定義屬性的應用模式,放到團隊所需要連線合作的每一個目標中。對於這個例子來說,我們把 "tid" 屬性附加到了目標元素上。

這裡需要強調的一個技術上的注意事項是 CSS 選擇器的限制。CSS 選擇器是不允許像 XPath 一樣選擇父元素的。這是為了避免頁面上 CSS 樣式的無限迴圈。這對網頁設計來說是件好事,但是,當它作為自動化的元素選擇器時是一種限制。幸運的是,這種限制可以由開發實現自定義屬性來避免。QA 應請求合適的自定義屬性,以便無需選擇父元素。

如果你們公司的開發部門和 QA 團隊不存在合作文化的話,也不用擔心!應該實施這個策略,因為它是可以推動合作的途徑。無論這種合作文化是否存在,你也應該先採用這種方式然後看看效果怎麼樣。你不但會擁有一個易於維護的選擇器策略,你還會看到遍及整個公司的協作文化所帶來的便利。這種合作關係會在質量保障的多個方面受益,比如減少缺陷,縮短上市時間並提高生產力。

為了更好地實行這個策略並建立合作關係,QA 團隊應該從一開始就參與到設計過程中,與開發部門合作並 review 需求。隨著開發部門設計功能,QA 應該建議哪裡可以實現自定義屬性的位置,以最好地支援自動化工作。通過在設計階段初期就鼓勵這種合作,能夠讓 QA 團隊和開發部門會在合作關係中走得更近,提高開發效率。這也可能會對軟體開發週期的其它領域產生溢位效應。在鼓勵開發部門與 QA 團隊的合作中,他們彼此更將熟悉,同樣的,這種關係也會對映到其它領域的合作中。

舉個栗子:

在示例 HTML 程式碼中的錨點元素上使用自定義屬性:

<div id="main-menu">
  <div class="menu"><a tid="home-link" href="/home">Home</a></div>
  <div class="menu"><a tid="shop-link" href="/shop">Shop</a>
    <div class="submenu">
      <a tid="gizmo-link" href="/shop/gizmo">Gizmo</a>
      <a tid="widget-link" href="/shop/widget">Widget</a>
      <a tid="sprocket-link" href="/shop/sprocket">Sprocket</a>
    </div>
  </div>
</div>
複製程式碼

注意,一些元素上有了新屬性。我們建立了一個叫 "tid" 的新屬性,與標準的 HTML 屬性並無任何充衝突。有了自定義屬性,我們可以通過一個 CSS 元素選擇器去定位它:

driver.find_element(By. CSS_SELECTOR, "[tid=home-link]")
複製程式碼

假設,你想選擇選單中所有的連結,無論一級選單還是二級選單。你可以通過 CSS 選擇器,建立靈活多變的元素選擇器組:

driver.find_element(By.CSS_SELECTOR, "#main-menu [tid*='-link']")
複製程式碼

"*=" 做的是,在所有元素的 "tid" 欄位中由萬用字元搜尋 "-link"。把它放到 "#main-menu" ID 選擇符的後面,它就只搜尋主選單內的元素了。

如果你想脫離自定義屬性來使用這個策略,也依然是正確路線。舉例說,你可以通過如下方式定位到 Shop 的子選單中的連結:

driver.find_element(By. CSS_SELECTOR, "#main-menu .submenu a")
複製程式碼

這一策略可以使得工程師建立易於維護且不受 UI 介面中無關變化影響的自動化工作。選擇這一策略是最好的方法。這不僅是一個易於維護的自動化解決方案,而且還會鼓勵 QA 團隊和開發人員之間的合作。

總結:具有自定義屬性的 CSS 選擇器

優點 缺點
學習難度低 初始階段就涉及到與開發人員合作
豐富的線上支援
靈活多變
超級棒的相容性

結論

在自動化框架中實現企業標準級的元素選擇器策略有一些很好的選擇。應該避免選擇像是標籤名或連結文字選擇器,除非它們是你唯一的選擇。XPath,ID 和 Class 選擇器則是一個好路線。到目前為止,最好的方法是實現自定義屬性並用 CSS 選擇器來定位。這也鼓勵了開發部門與 QA 團隊之間的合作。

這是所有選項的比較表:

1511434384(1).jpg


掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章