美文网首页UI 自动化
Appium 元素定位方式大揭秘

Appium 元素定位方式大揭秘

作者: DC_ing | 来源:发表于2017-08-21 17:00 被阅读0次

    前言

    相信大家在使用 Appium 时,都会遇到过一个问题,怎么更好地在一个页面中对某一个元素进行更快速的定位方式。本篇文章基于大家刚接触 Appium,对元素定位还是比较模糊。

    Appium 定位方式是依赖于 Selenium 的。所以 Selenium 的定位方式,Appium 都支持,还加上Android 和 iOS 原生的定位方式。这样一下来,就有十多种定位方式,挑选哪一种使用,也是有些讲究的。

    1. Appium 定位方式种类

    目前,Appium 支持的定位方式,如下所示:

    cssSelector             # Selenium 最强大的定位方法,比 xpath 速度快,但比 xpath 难上手
    linkText                # 链接元素的全部显示文字
    partialLinkText         # 链接元素的部分显示文字
    name                    # 元素的 name 属性,目前官方在移动端去掉这个定位方式,使用 AccessibilityId 替代
    tagName                 # 元素的标签名
    className               # 元素的 class 属性
    id                      # 元素的 id 属性
    xpath                   # 比 css 定位方式稍弱一些的定位方法,但胜在容易上手,比较好使用,缺点就是速度慢一些。
    AccessibilityId         # Appium 中用于替代 name 定位方式
    AndroidUIAutomator      # Android 测试,最强大速度最快的定位方式
    iOSNsPredicateString    # iOS 谓词的定位方式,仅支持 XCTest 框架,需大于 iOS 9.3或以上
    IosUIAutomation         # iOS 谓词的定位方式,仅支持 UIAutomation 框架,需大于 iOS 9.3或以下
    iOSClassChain           # 国外大神 Mykola Mokhnach 开发类似 xpath 的定位方式,仅支持  XCTest 框架,,不如 xpath 和 iOSNsPredicateString 好
    windowsAutomation       # windows 应用自动化的定位方式
    

    上述所示的定位方式中,name由于官方的原因废弃掉,所以不在这里赘述了。tagNamelinkTextpartialLinkText 在我的理解中,一般是在 web 页面使用,移动端很少用。

    接下来,说一下我认为在 App UI自动化中常用到定位方式的详细用法。

    1.1 className

    使用元素的className属性定位,支持:Android 和 iOS,推荐使用。

    MobileBy.className("XCUIElementTypeButton")
    

    1.2 id

    使用元素的resource-id属性定位,支持:Android,仅支持 Android 4.2或以上,推荐使用,一般来说,使用 id 能准确定位,就使用 id 吧,定位信息简洁,不容易错误。反正我没有在 iOS 用过,大家有正确使用过的例子,可以分享一下。

    MobileBy.id("package.name:id/android")
    

    1.3 xpath

    支持:Android 和 iOS。但由于 iOS 10开始使用的 XCUITest 框架原声不支持,定位速度很慢,所以官方现在不推荐大家使用,也有其他替代的定位方式可使用。

    1. 使用绝对路径定位,如截图所显示的 xpath 路径

      MobileBy.xpath("className/className/className/className")
      
    2. 使用相对路径定位

      MobileBy.xpath("//className")
      
    3. 通过元素的索引定位

      MobileBy.xpath("//className[index]")
      
    4. 通过元素的属性定位

      MobileBy.xpath("//className[@label='更多信息']")    # 使用一种属性定位
      
      MobileBy.xpath("//className[@label='更多信息'][@isVisible='1']")    # 使用两种属性定位
      MobileBy.xpath("//className[contains(@label,'更多')]")    # 使用部分属性定位(最强大)
      

    1.4 AccessibilityId

    替代以前的name定位方式,推荐使用。
    在 Android 上,主要使用元素的content-desc属性,如该属性为空,不能使用此定位方式。
    在 iOS 上,主要使用元素的labelname(两个属性的值都一样)属性进行定位,如该属性为空,如该属性为空,也是不能使用该属性。

    MobileBy.AccessibilityId("更多信息")
    

    1.5 AndroidUIAutomator

    仅支持 Android 4.2或以上,可支持元素的单个属性和多个属性定位,推荐使用。

    支持元素以下属性定位:

    index(int index)
    text(String text)
    resourceId(String id)
    className(String className)
    packageName(String packageName)
    description(String desc)
    checked(boolean val)
    clickable(boolean val)
    enabled(boolean val)
    longClickable(boolean val)
    selected(boolean val)
    instance(int val)
    # 其他一些详细方法(包括正则表达式匹配),请查看 Android 源码中,UiSelector 类定义的方法
    

    例子:

    MobileBy.AndroidUIAutomator("new UiSelector().text(\"发送\")")    # 使用一种属性定位
    MobileBy.AndroidUIAutomator("new UiSelector().text(\"发送\").clickable(true)")    # 使用两种属性定位
    

    元素的所有属性都可用做定位,功能非常强大,且速度很快。

    1.6 iOSNsPredicate

    仅支持 iOS 10或以上,可支持元素的单个属性和多个属性定位,推荐使用。详细请参照
    iOSNsPredicate 定位

    MobileBy.iOSNsPredicateString("type == 'XCUIElementTypeButton'")    # 使用一种属性定位
    MobileBy.iOSNsPredicateString("type == 'XCUIElementTypeButton' AND label == '更多信息'")    # 使用两种属性定位
    

    具体 iOSNsPredicate 语法结构可查看官方文档,或查看我另外的一个帖子。

    1.7 iOSClassChain

    仅支持 iOS 10或以上,这是 github 的 Mykola Mokhnach 大神开发,仅限在 WebDriverAgent 框架使用,用于替代 xpath 的,但使用一阵子后,感觉灵活性没有 xpath 和 iOSNsPredicate 好,应该还不完善吧。具体使用方法,请见:iOSClassChain

    MobileBy.iOSClassChain('XCUIElementTypeWindow[1]/XCUIElementTypeOther[1]/XCUIElementTypeOther[1]/XCUIElementTypeNavigationBar[1]/XCUIElementTypeOther[1]/XCUIElementTypeButton[2]')
    

    1.8 IosUIAutomation

    仅支持 iOS 9.3或以下,是 iOS 旧框架 UIAutomation 的定位方式,这个定位类型同样可使用 iOS 谓词进行定位,详细可参考:iOSNsPredicate

    MobileBy.IosUIAutomation("type == 'UIAButton'")     # 使用一种属性定位
    
    MobileBy.IosUIAutomation("type == 'UIAButton' AND label == '更多信息'")    # 使用两种属性定位
    

    2. 元素复杂定位

    在贝聊家长版 Android 的登录页面中,手机号码输入框和密码输入框两个元素信息如下图所示。

    图1 图2

    手机号码输入框和密码输入框大部分属性都一致,单独使用 className 和 id 已经不可行了。可能有同学问,输入框不是有默认文案(text 属性)吗?使用text 属性定位就可以啦。
    在初始登录时,使用这个text 属性定位的确可以,但如果不是初始登录,手机号码输入框残留上次登录的手机号码,text 属性就变成上次登录的手机号,如 图3 所示。

    图3

    在类似这样的输入框中,元素的 text 属性会不断变化。在进行元素定位时,我们会尽可能避免使用可变化值的属性进行定位。

    由此可见,手机号码、密码两个输入框基本上不能使用单一属性进行定位,如果这样的话,我们可以使用元素多属性进行定位。观察图1和图2,两个元素的属性大部分一致,但还是有3个属性是不同的:focused、password、instance。再结合只有两个输入框相同的属性值,这样一定位,即可找到该元素了。

    使用 AndroidUIAutomator 定位。UiSelector 不支持 password 属性定位。

    # 手机号码输入框
    MobileBy.AndroidUIAutomator("new UiSelector().resourceId(\"com.babychat:id/edit_content\").focused(true)")
    MobileBy.AndroidUIAutomator("new UiSelector().className(\"android.widget.EditText\").instance(0)")
    
    # 密码输入框
    MobileBy.AndroidUIAutomator("new UiSelector().resourceId(\"com.babychat:id/edit_content\").focused(false)")
    MobileBy.AndroidUIAutomator("new UiSelector().className(\"android.widget.EditText\").instance(1)")
    

    使用 xpath 定位,不支持使用 instance 属性定位

    # 手机号码输入框
    MobileBy.xpath("//android.widget.EditText[@focused='true']")
    MobileBy.xpath("//android.widget.EditText[@password='false']")
    
    # 密码输入框
    MobileBy.xpath("//android.widget.EditText[@focused='false']")
    MobileBy.xpath("//android.widget.EditText[@password='true']")
    

    3. 总结

    Appium 元素的一些定位方式,大体上就上面跟大家所说的那样。只要能将你想要的元素定位到,具体使用哪个,就得看个人习惯了。但如果想要定位的元素,其属性与其他元素相似较多的话,就需要使用两种甚至三种属性进行定位了,具体使用哪些属性,就得跟其他属性一一对比,找出不相同的属性,根据属性来使用定位类型,这样比较靠谱一些。

    本篇文章是本人在学习 Appium 中所得到的感悟,如果大家有更好的方法,也可以说出来,大家一起讨论,一起进步!

    相关文章

      网友评论

        本文标题:Appium 元素定位方式大揭秘

        本文链接:https://www.haomeiwen.com/subject/cschdxtx.html