1. 程式人生 > >Appium-關於appium的原生控件的 xpath 定位問題及常用方法

Appium-關於appium的原生控件的 xpath 定位問題及常用方法

相對路徑 使用 都是 classname 按鈕 bsp ref android 這樣的

最近遇到的項目,發現很多元素,都沒有標明id、text、content-desc,classname中又有很多是相同,導致無法定位

  技術分享

  第一,appium1.5及之後的版本廢棄了name屬性(如name=賬單,將不被支持用於定位),所以基本的定位就用下id就好了。其他的不多說了。

  第二,下面就來說一下關於xpath的定位。主要場景為沒有id或者沒有text,或者text是一個不可控的值(或者叫會發生變化的值,就比如text字段為10元,可能這個10每次會變)的時候。其實簡單點就是按路徑定位包括一級或者多級路徑。順便說一下,路徑方式分兩種,一種是絕對路徑(以第一個標簽為參照物),另一種是相對路徑(已其他已知的標簽為參照物),且在定位的時候盡量采用相對路徑的方式。

  1,先說說有id或者text的場景使用xpath的情況。(有id或者name為什麽不直接用?以下均為相對路徑)

  上面說的name被廢棄了,但是xpath的寫法如//android.widget.TextView[@text="賬單"]是被支持的

  就比如上面的"賬單"和"我要"的id都是com.wlqq:id/title_left_btn,並且假設當前頁面只有這兩個位置id為前面寫的,那麽你在用id定位"賬單"的時候,就可以用xpath了,因為id已經不唯一了。

    用id定位“賬單”的為:

      xpath=(//android.widget.TextView[@resource-id="com.wlqq:id/title_left_btn"])[1],

    定位"我要"的為:

      xpath=(//android.widget.TextView[@resource-id="com.wlqq:id/title_left_btn"])[2]

   此處註意三點:
    a,下標是從1開始,而不是0;
    b,如果有下標,需要用括號把前面的部分括起來,並且前面需要加xpath=,可能有些人習慣了前面都加xpath=,但是像我這種只習慣寫//開頭,不寫xpath=的就被坑慘了。。。反正不容易發現是因為沒有寫xpath=,也可能是我個人比較坑吧。
    c,就是和web不一樣的就是標簽的取值,在這裏取的是class的值=android.widget.TextView而不是看到的標簽TextView,具體原因沒有深究。反正記住用class代替標簽就對了。
另外,上面的只是為了說明只有1個層級的時候xpath的用法,1層也算是一種相對路徑吧。因為沒有從第一個位置的屬性開始寫。xpath的書寫規則基本是越少越好。所以層級也是越少越好。有1層可以唯一定位就不要2層。 可能有點廢話了。

  2,現在就來說說沒有id或者name的場景。 先來一張圖:

    技術分享

    現在有一個場景是,我要定位到我需要點擊上面那個小人圖標,但是沒有text、id、content-desc,唯一classname還是和其它相同,能想到的方法是用xpath方式

    用絕對路徑的寫法就是:如果圖上的第一個是最頂上的話,就是:

      技術分享

    這樣的,也就是需要7個層級,依次寫下來就是:
    //android.widget.LinearLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.RelativeLayout/android.widget.RelativeLayout/android.widget.LinearLayout[2]/android.widget.ImageButton

    這種寫法註意一下幾點:

      a , [2]註意是2而不是3,因為與標簽的值有關。只有2個LinearLayout。

      b , 路徑長度偏長,而且因為只有class的值,對於一些頁面控件較多的,可能不止一個,也就是可能這種寫法也都不是唯一。

      c , 絕對路徑基本很少使用,如果人品太差,遇到頁面全是沒有id或者name的,那就沒辦法了。或者考慮一些坐標。

  3,(重要)沒有id或者name的場景下使用相對路徑的辦法來定位。主要介紹一下層級關系中的父子關系(上下級)和兄弟關系。

    大家可以看到,這個圖裏面有一個唯一的中文詞匯--"錢包"。我們可以通過這個錢包來定位我們的小人圖片。先分析下位置關系

    技術分享

    找找關系也就是如圖所示,小人圖標3是錢包1的弟弟2LinearLayout標簽的兒子ImageButton。兒子好理解,xpath的層級關系也就是父子關系用/表示。//android.widget.LinearLayout/android.widget.ImageButton這樣就能表示弟弟的兒子了。但是現在問題是怎麽表示錢包的弟弟?xpath裏面有一個軸,簡單點可以理解為一個函數吧。我這樣認為的。preceding-sibling:: 可以找到節點前面也就是哥哥節點,following-sibling::可以找到節點後面也就是弟弟節點,關於軸的更多用法啊,可以自行百度xpath的語法。這裏還有一個用的多的就是parent:: ,可以找到節點的父親節點。但是父親節點可以用..表示。下面就來具體說一下怎麽用:

    基本知識已經介紹到此了。那麽這裏的定位方法就是上圖中的3個層級://android.widget.TextView[@text="錢包"]/following-sibling::android.widget.LinearLayout/android.widget.ImageButton。 第一級就同前面說的唯一的找到錢包這個位置,後面的一級就是錢包的弟弟,也就是following-sibling::android.widget.LinearLayout。當然註意因為是緊挨著的,所以弟弟沒有下班,可想而知如果是第幾個弟弟,就加個下標吧。哥哥也是同理。

    前面用到了兄弟的關系,下面說一下兒子與父親的關系。父子關系還是用圖來說明

      技術分享

    我們的錢包1的父親2有一個兒子3的兒子4就是我們的小人圖標。這就是找關系。關系找到了,那我們就可以用這個關系來寫xpath了。

    也就是錢包(//android.widget.TextView[@text="錢包"])的父親(/parent::android.widget.RelativeLayout )的第二個class=android.widget.LinearLayout的兒子(/android.widget.LinearLayout[2])的兒子(小人/android.widget.ImageButton),好,我們連起來就是://android.widget.TextView[@text="錢包"]/parent::android.widget.RelativeLayout/android.widget.LinearLayout[2]/android.widget.ImageButton。

    順便說一下父親這個位置可以用..來代替,相比很多人都知道..在路徑裏面指的就是上級。所以可以用//android.widget.TextView[@text="錢包"]/../android.widget.LinearLayout[2]/android.widget.ImageButton這個來代替上面的寫法。
    註:最後再強調下,關於這個地方,下標為什麽是[2],是因為只與class相同的有關。錢包的class不一樣。所以它就不算了。

  關於相對路徑的父子關系,以及兄弟關系,相比大家應該有所體會了吧。如果還是沒太懂,咱們再來個復雜點的例子。可能只是舉例說明下語法。實際下面的可能不會這樣復雜的寫。先上圖:

    技術分享

    假設我們需要通過加入購物車這個位置來定位我們的立即定位按鈕,那麽,我們的一種寫法就是圖上的這個關系7層級。也就是加入購物車7(//android.widget.TextView[@text="加入購物車"])的父親1(/..)的父親2(/..)的父親3(/..)的第二個兄弟4(/following-sibling::android.view.View[2])的兒子5(/android.view.View)的兒子6(也就是我們的立即購買/android.widget.TextView),

    連起來就是

    //android.widget.TextView[@text="加入購物車"]/../../../following-sibling::android.view.View[2]/android.view.View/android.widget.TextView。

    註意:使用text的時候避免使用輸入框的默認輸入值,因為當你真實輸入值之後,就沒有這個text了,也就找不到路徑了。另外也可以用模糊匹配,xpath有一個contains函數。用法//android.widget.TextView[contains(@text,"購物車")].也能找到“加入購物車”這個位置。

    技術分享

    場景:定位請輸入密碼這個輸入框,上圖,沒有id、text、content-desc,classname也有很多重復

    使用xpath,手寫定位

    1、先選取登錄按鈕作為節點

      //android.widget.TextView[@text=‘登錄‘]

    2、再定位到父級

      /.. 也就是  /parent::android.view.View

    3、再定位同級的哥哥

      /preceding-sibling::android.view.View[1]  

      註意:[1],下標是向上數的,適用於preceding-sibling

        如果是following-sibling,則向下數的

        都是從1開始取下標

    4、再定位到孩子

      child::android.widget.EditText

  連起來就是:

    //android.widget.TextView[@text=‘登錄‘]/../preceding-sibling::android.view.View[1]/child::android.widget.EditText

        

Appium-關於appium的原生控件的 xpath 定位問題及常用方法