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

        

时间: 2024-11-06 17:05:47

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

appium自动化测试(3)-控件定位&中文输入

参考-控件定位 http://www.2cto.com/kf/201410/340345.html appium接口 http://appium.io/slate/en/master/?python#about-appium ◆ 控件定位就是精确的描述控件特征并告诉机器的过程.控件的特征就是控件的属性,可以通过上一讲中的uiautomatorviewer去获取.以下是方法: 1.通过resourceID获取 driver.find_element_by_id("com.android.conta

一个Demo带你认识Design库,纯原生控件也能做出很漂亮的效果

欢迎转载,转载请注明出处http://blog.csdn.net/w804518214/article/details/51340984 不得不说开发者头条的APP真的是Material Design的典范,纯原生控件也能做出很漂亮的效果,并且不需要处理各种复杂的滑动冲突!!其主页基本把Design库的几个控件展示了一遍,今天就顺手借开发者头条主页的实现来简单介绍下官方Design扩展包里几个控件的使用.本文不会详细展开讲每个控件,仅仅针对demo效果的实现,想深入研究的推荐看官方指南! 先上效

论如何在手机端web前端实现自定义原生控件的样式

手机开发webapp的同学一定遇到过这样问题,如何为丑极了的手机元素应用自定义的样式.首先,要弄清楚为什么要定义手机原生控件的样式,就需要看看手机的那些原生框样式的丑陋摸样: android: ios: 无奈的选择 看完了这些丑陋的界面元素,我们就可以理解当我们把他们暴露在产品同学的眼中时,那种层层的杀气了.可以看到,界面元素十分丑陋,产品兄弟是肯定不会接受的.但是,不得不说这些控件在触发后的效果比pc机上的要炫酷.这其中以apple机的滚筒选择最为出色.以下是它们触发后调用原生控件的效果: a

JS与APP原生控件交互

"热更新"."热部署"相信对于混合式开发的童鞋一定不陌生,那么APP怎么避免每次升级都要在APP应用商店发布呢?这里就用到了混合式开发的概念,对于电商网站尤其显得重要,不可能每次发布一个活动,都要发布一个现版本,当然这样对于Android还算可以,但是对于Ios呢?苹果应用商店每次审核的时间基本都在1~2周,这对于一个促销活动来说审核时间实在太长.而混合式开发正好可以解决这个问题,基本的原理时,通过原生控件实现APP的主体结构,借助H5开发对应的页面,这样每次发布活

JS调用Android、Ios原生控件

在上一篇博客中已经和大家聊了,关于JS与Android.Ios原生控件之间相互通信的详细代码实现,今天我们一起聊一下JS调用Android.Ios通信的相同点和不同点,以便帮助我们在进行混合式开发时,提高代码质量,实现两者在网页端代码的统一. 首先我们先看一下Ios调用JS的方法实现: //无参调用 function SwiftCallJs1(){} //有参调用 function SwiftCallJs2(name, message){} 紧接着我们看一下Android调用JS的方法实现: /

【Android界面实现】使用ActionBar和DrawerLayout纯原生控件,实现侧滑栏和滑动Tab界面

转载请注明出处:http://blog.csdn.net/zhaokaiqiang1992 在前面的文章中,我们使用第三方开源控件,比如说是SlidingMenu和PagerSlidingTabStrip,实现过侧滑栏和滑动Tab界面.但是在support-v4包中,提供了原生的侧滑栏控件DrawerLayout,而滑动的Tab效果,我们可以使用ViewPager和ActionBar上的Tab来进行实现.所以在今天的文章里面,我们将介绍如何将DrawerLayout与ActionBar进行整合,

Phonegap 原生控件(Android)与html混合

1. 用命令创建cordova项目 cordova coreate hello com.example.hello hello 2.打开MainActivity 在onCreate方法中加入 setContentView(R.layout.main_activity); 3. main_activity文件如下: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android=&

WPF自定义控件(二)の重写原生控件样式模板

开发过程中,我们有时候用WPF原生的控件就能实现自己的需求,但是样式.风格并不能满足我们的需求,那么我们该怎么办呢?----自定义样式与模板. 一.样式 在WPF中我们可以使用Style来设置控件的某些属性值,并使该设置影响到指定范围内的所有该类控件或影响指定的某一控件,比如说我们想将窗口中的所有按钮都保持某一种风格,那么我们可以设置一个Style,而不必分别设置每个按钮的风格.Style是作为一种资源被保存下来的. 看下面的例子: <Style x:Key="style1" T

[iOS] Edit / Memo 原生控件才提供拼字检查

在 iOS 平台提供了英文拼字检查,但需将 ControlType 设定为 Platform 才能使用: 效果: