1. 程式人生 > >為Selenium Webdriver 測試編寫可靠定位器

為Selenium Webdriver 測試編寫可靠定位器

原文地址:https://blog.mozilla.org/webqa/2013/09/26/writing-reliable-locators-for-selenium-and-webdriver-tests/

        假如你來這裡是要尋找一個完美的,牢不可破的定位器,那我恐怕要告訴你,世界上沒有完美的定位器。HTML更改和定位器不相容是編寫 UI 自動化測試所面臨的現實。只要您的web應用程式在演進,比如說隨著開發團隊嘗試新的設計、簡化HTML和修復錯誤,這時候你不得不更新你的定位器。維護定位器必然成為測試維護成本的一部分。

        然而,好訊息是,好的和糟糕的定位器之間是有區別的。這意味著如果能設計好你的定位器,你就可以降低維護成本,這樣你就可以把時間集中在更重要的工作上,而不是除錯錯誤的結果(由於locator的原因導致的錯誤----筆者加)

        另一方面,一次失敗的定位是個好事情,所以不要害怕。信任“NoSuchElementException”遠比斷言失敗好,因為這通常提醒你的軟體該進行迴歸測試了。

        在本指南中,我假設你已經知道了如何編寫定位器,並且熟悉CSS和XPath定位器的構造和語法。從這裡開始,我們將探究在編寫Selenium測試時,一個好的定位器和一個壞的定位器的區別。

IDs 是國王

        ID 是最安全的定位選項,應該始終是你的首選。按照W3C的標準,一個元素的id值在頁面中是獨一無二的,這意味著你永遠不會遇到一個問題,即找到多個匹配定位器的元素。

        ID 也是獨立於樹外的元素型別和位置,因此如果開發人員移動了元素或者更改了其型別,WebDriver 仍然可以找到它。

        ID 經常用於Web頁面的JavaScript中(事實上,大多數開發並不是同情測試人員定位元素困難才給元素加上ID的,而是他們自己需要用到才會加),因此開發人員會避免更改元素的ID,因為這將導致他們更改自己的JavaScript。不管怎樣,這對我們測試人員來說太棒了。

        假如你身邊恰巧遇到“靈活”的開發,甚至一隻眼放在app 原始碼上(一半的精力),你可以嘗試著在週五晚上給他買一杯啤酒,嘗試和他們的妹妹約會,或者就是直白的乞求,以期望他們能往程式碼里加入更多的ID。當然大多數情況下,這都是不切合實際的或者不可行的,所以我們需要使用CSS 或者 Xpath 定位器。

CSS 和 XPath 定位器

        CSS和XPath 定位器在概念上非常相似,所以我們把它們放在一起討論。

這些型別的定位器組合了標籤名、後代元素、CSS類或元素屬性,是的匹配模式嚴格或寬鬆。嚴格是說,小的HTML變化都會使其失效,或者它可能會匹配多個HTML元素。

        當編寫CSS 或 XPath 定位器時,我們需要在嚴格和鬆散之間找到平衡點。使其既能夠儘可能久的適應HTML的變化;當應用程式出現錯誤時,也能足夠嚴格的反應出來。

找到一個錨點元素

        使用CSS 或 XPath 定位器的一個好方法是,首先找到一個不太可能改變的元素,使其作為你的定位器錨點。這個錨點可能有個ID,或者是個穩定的位置,這不是你需要定位的元素但時一個可靠的搜尋位置。你的錨點元素可以在HTML樹的當前元素(目標元素)之上或之下,但大多數情況選擇目標元素上面的元素作為錨點。

<div id=”main-section”>
    <p>Introduction</p>
    <ul>
      <li> Option 1</li>
    </ul>
</div>
        在本例中,我們想要定位<li>元素沒有ID 或 一個CSS 類標記它,因此很難定位。尤其是還有可能在HTML中有多個列表。div 有個id=“main-section” 可以選為尋找<li>的錨點元素,這樣就縮小了定位器正在搜尋的HTML(從錨點往下找,不用找正個HTML了)

何時使用“索引”定位器,如 nth-child()  and [x]

        nth-child(), first-child, [1] 和這些索引型別的定位器只能應用於列表物件。這種情況,測試應該明確知道想要從列表中選擇的專案對應哪個索引,例如可以驗證一下搜尋結果的第一項來驗證一下(index[0],不知道list有幾個元素,那就列印下第一個元素)。使用一個索引型別的定位器來定位一個不是索引位置的元素,當這個元素的順序發生改變的時候,可能會引起問題,因此應該避免這種情況。

<menu>
  <button>Option 1</button>
  <button>Option 2</button>
  <button>Option 3</button>
</menu>

假如不管列表項如何排序,你都只想要與第一個選單項進行互動時,那麼 //menu/button[1]  是一個合適的定位器。如果不是(大多數情況下,我們是想選擇列表中的某一項,比如這裡的Option 1),而如果button的順序改變成下面這樣,而你還通過 //menu/button[1]  進行定位的時候,就會定位到Option 3,就會導致測試失敗。

<menu>
  <button>Option 3</button>
  <button>Option 2</button>
  <button>Option 1</button>
</menu>
這是一個合理的失敗?還是需要你重新編寫定位器。

        根據您測試的目標,非索引定位器,//menu/*[text()=’Option 1’]  可能更合適。這時候<menu>是理想的錨點元素。

CSS 類名稱經常透露他們的用途

        前端設計人員實際上也是人,他們經常會給CSS 類名稱來表示他們的目的。

        我們應該利用這一點,選擇依賴功能而不是樣式的定位器,因為樣式通常是會改變的。

<footer class="form-footer buttons">
  <div class="column-1">
      <a class="alt button cancel" href="#">Cancel</a>
  </div>
  <div class="column-2">
      <a class="alt button ok" href="#">Accept</a>
  </div>
</footer>
    在上面這個示例中,忽略class column-1和column-2 比較好。他們指的是佈局,因此當開發決定調整設計(調整佈局)的時候,他們可能會受到變化影響。如果我們能直接對目標按鈕(Accept和Cancel按鈕)進行操作會更加可靠。雖然button ok 在頁面上可能不止一個,看起來像個鬆散的定位器。但是你可以將頁尾作為錨點元素,在這個例子中“,從下往上”定位button ok 是一個好的定位器。

發現未來的脆弱性(易變性)

        通過觀察HTML,你可以發現潛在未來脆弱性。在離開前面的例子時,我故意留下了超過3個定位器以外的問題。比如說<a> 是一個tag name,<a>後面跟的文字內容,在HTML中,看起來開發人員已經把 text label 改成ok,並且tag改成了button。結果導致class,text content,tag name都匹配不到了。

<footer class="form-footer buttons">
  <div class="column-1">
      <a class="alt button cancel" href="#">Cancel</a>
  </div>
  <div class="column-ok">
      <button class="alt ok">ok</button>
  </div>
</footer>
如果開發團隊優柔寡斷或嘗試使用UX和效能改進,這些也可能會變。我們接下來使用鬆散的定位器,這將容忍HTML中的一些變化。接下來讓我們在鬆散定位器上犯錯,嘿嘿。

直接派生(通過父節點找子節點)

CSS example: div > div > ul > li > span
Xpath example: //div/div/ul/li/span

直接派生類是指HTML 元素的父子關係。在第一個示例中,<li>是<url>的子元素。

在上面的示例中,使用長鏈的話可能會幫助你找到一個沒有class或者id的元素,但從長遠來看,他肯定是不可靠的。在沒有id或類的情況下,大段的內容是經常動態變化的。而且可能經常移動或在HTML中變換位置。它只需要在鏈條中找到一個元素然後順著找下來。

如果你不得不使用直接派生類的定位器,那麼嘗試在每個定位器中最多使用一個。

根據你的目標去調整

<section id=”snippet”>
    <div>Blurb</div>
</section>

只使用你需要的定位器。少即是多! 如果您只是捕獲文字,那麼使用“# snippet div”這樣的定位器是沒有必要的。WebDriver將返回定位器# snippet和' #snippet > div的相同文字內容,但是如果div元素被更改為< p >或< span >,則後者將會失效。

定位元素的屬性

定位屬性和通過CSS類定位非常類似,屬性可以是唯一的,但有的時候也會在許多項中重複使用,你必須視情況而定到底什麼時候用他。

一般來說,最好避免使用屬性,只關注id、tag和css類,但在HTML 5 中,資料屬性是穩定的屬性,因為它們與web應用程式的功能緊密結合在一起。

tag name、link text, name 的定位策略

這些定位策略只是通過屬性或文字字串查詢的快捷方式(Xpath:text())。使用這些規則的規則也適用於標籤名稱、連結文字和名稱。
綜上所述:當您在編寫一個定位器時,首先查詢一個ID,然後使用ID(作為錨定元素)的下一個最近的元素。從那裡,看下派生和元素屬性,以縮小到要定位的元素。
確切地理解定位器的用途——它僅僅是在站點中導航還是斷言元素的順序?如果單元移動或測試失敗,定位器是否能夠處理?
定位器的用途將決定你需要在定位器中使用的技術有多嚴格、多寬鬆。
祝您好運,並明智地為您節省未來的測試維護和假的負面爭論!