xpath定位和web上的不同點:
先放一個圖:

第一,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的場景。 先來一張圖:

現在有一個場景就是我需要點擊上面那個小人圖標,但是他沒有id和text屬性。能想到的辦法就是下面要講的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,"購物車")].也能找到“加入購物車”這個位置。自行體會去吧。。。
