• Appium-关于appium的原生控件的 xpath 定位问题及常用方法


    最近遇到的项目,发现很多元素,都没有标明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

            

  • 相关阅读:
    【高软作业4】:Tomcat 观察者模式解析 之 Lifecycle
    Eclipse 导入 Tomcat 源码
    【高软作业3】:原型化系统 DevTools
    Java Obejct
    Java PriorityQueue
    【高软作业2】:Java IDE调研分析
    GitHub fork 合作开发 快速实现版
    用C#实现天气预报(调用WebService)
    hover和点击事件之间的冲突
    BurpSuite2021系列(三)新建扫描
  • 原文地址:https://www.cnblogs.com/R-bear/p/7569616.html
Copyright © 2020-2023  润新知