美文网首页
iOS 元素定位总结

iOS 元素定位总结

作者: 米不开朗基罗 | 来源:发表于2021-04-28 19:39 被阅读0次

    [TOC]

    一:Appium 元素定位工具安装

    第一种:通过Appium1.6的Inspector来查看

    image-20210428191959877

    可以通过定位找到元素xpath或name

    个人不推荐用这个方法,实际操作中发现,每次操作后点击刷新比较慢,而且有时左侧布局文件更新不及时,导致点击左侧屏幕的控件找不到元素,有时App Source根本就没更新

    第二种:通过macaca的App inspector来定位元素

    1.安装macaca-li

    $ npm install macaca-cli -g
    

    2.检查macaca环境

    $ macaca doctor
    

    只要打印出的结果都绿色的日志信息,就表示环境是好的

    3.安装app-inspector

    $ npm install app-inspector -g
    

    4.使用方法

    通过下面命令启动检测web界面,然后就在Safari中自动打开了【http://本地IP:5678】进行检测

    $ app-inspector -u YOUR-DEVICE-ID(设备id)
    

    iOS获得设备id的方法:

    真机的获取方法:idevice_id -l

    $ xcrun simctl list
    

    获得下面的数据:

    image-20210428192104366

    第一个括号内的就是手机的device id,第二个括号内是模拟器的状态

    结果如下,也可以获得元素的name和xpath

    image-20210428192129187

    说明:我目前使用第二种方式,

    1是直接刷新页面速度比appium中快点;

    2是没有很大延迟,刷新后点击元素图标一般都能找到元素

    (使用时还遇到过一个问题,web打开时手机界面底部没展示全,通过键盘command和-号组合缩小页面,展示了全部内容)

    遇到的问题:app-inspector我这用的模拟器,用真机的情况下一直报错。模拟器没问题

    Error: connect ECONNREFUSED 127.0.0.1:8001
    
       at Object.exports._errnoException (util.js:1024:11)
    
       at exports._exceptionWithHostPort (util.js:1047:20)
    
       at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1150:14)
    
     
    

    解决方法:

    cd /usr/local/lib/node_modules/app-inspector/node_modules/xctestwd/XCTestWD
    
    open XCTestWD.xcodeproj
    

    修改XCTestWD和XCTestWDUITests,修改bundle id,签名然后编译通过即可。(参考webdriveragent的更改方法,操作一致)

    image-20210428192213007

    二:iOS定位元素

    总结一下IOS定位方式和各个定位方式的速度排序。


    据我观察,按查找元素的顺序速度,从快到慢的顺序如下:

    ios_predicate >> accessibility_id >> class_name >>xpath

    注⚠️:(论坛比较多的说法是class_name>>accessibility_id,在这里我们姑且认为它们的速度是一样的。)

    1. 元素属性介绍
    image-20210428192317841

    type:元素类型,与className作用一致,如:XCUIElementTypeButton
    value: 一般不用
    name:元素的文本内容,可用作 AccessibilityId定位方式,如:ClearEmail
    label:绝大多数情况下,与 name 作用一致
    enabled:元素是否可点击,一般值为true或者false
    visible;元素是否可见,一般值为true或者false

    1. ios_predicate

    在 iOS 的 UI 自动化中,使用原生支持的Predicate定位方式是最好,可支持元素的单个属性和多个属性定位,强烈推荐使用。
    使用方法,举例如下:

    driver.find_element_by_ios_predicate("value == 'ClearEmail'")
    driver.find_element_by_ios_predicate("type == 'XCUIElementTypeButton' AND value == 'ClearEmail'")
    

    1)比较运算符:>、<、==、>=、<=、!=
    可用于数值和字符串的比较:
    如:value>100value == 'ClearEmail'value != 'ClearEmail'

    driver.find_element_by_ios_predicate("value>100")
    

    2)范围运算符:IN、BETWEEN
    可用于数值和字符串的范围核对
    如:value BETWEEN {1,6}value IN {'Clear','Email'}

    driver.find_element_by_ios_predicate("value BETWEEN {1,6}")
    

    3)字符串相关:CONTAINS、BEGINSWITH、ENDSWITH
    包含某个字符串,如:value CONTAINS 'Email'
    以某个字符串开头,如:value BEGINSWITH 'Clear'
    以某个字符串结束,如:value ENDSWITH '班级Email'

    driver.find_element_by_ios_predicate("value CONTAINS 'Email'")
    

    4)通配符: LIKE
    其中:?代表一个字符,*代表多个字符
    如:一个元素的value属性为ClearEmail:
    value LIKE 'Clear?mail'
    value LIKE 'Clear*'
    以上这么多种文本都可以被识别为同一个元素。

    driver.find_element_by_ios_predicate("value LIKE 'Clear*'")
    

    5)正则表达式:MATCHES
    如:一个元素的value属性为ClearEmail:
    value MATCHES '^C.+l$'

    driver.find_element_by_ios_predicate("value MATCHES '^C.+l$'")
    

    注⚠️:正则表达式详情可参考《Python-正则表达式
    6)两种及两种以上属性定位元素:AND
    单个属性定位用符号AND连接起来即可,如下:

    driver.find_element_by_ios_predicate("type == 'XCUIElementTypeButton' AND value == 'ClearEmail'")
    

    1. accessibility_id

    替代以前的name定位方式,在 iOS 上,主要使用元素的labelname(两个属性的值都一样)属性进行定位,如该属性为空,也是不能使用该属性。
    driver.find_element_by_accessibility_id('ClearEmail')


    1. class_name

    使用元素的type属性定位,特别注意该属性的唯一性!class_name唯一的情况并不多,一般情况下用不上。
    driver.find_element_by_class_name('XCUIElementTypeButton')


    1. xpath

    由于 iOS 10开始使用的 XCUITest 框架原生不支持,定位速度很慢,所以官方现在不推荐大家使用,也有其他替代的定位方式可使用。
    1)使用绝对路径定位:
    driver.find_element_by_xpath('/XCUIElementTypeApplication/XCUIElementTypeButton')
    2)使用相对路径定位
    driver.find_element_by_xpath('//XCUIElementTypeButton')
    3)通过元素的索引定位
    driver.find_element_by_xpath('//XCUIElementTypeButton[index]')
    4)通过元素的属性定位
    一种属性:
    driver.find_element_by_xpath("//className[@value='ClearEmail']")
    两种属性:
    driver.find_element_by_xpath("//className[@value='ClearEmail'][@ visible =true]")
    部分属性(最强大):driver.find_element_by_xpath("//className[contains(@value,'ClearEmail')]")

    1. iOSClassChain

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

    find_element_by_ios_class_chain

    def find_element_by_ios_class_chain(self, class_chain_string):
            """Find an element by ios class chain string.
    
            Args:
                class_chain_string (str): The class chain string
    
            Usage:
                driver.find_element_by_ios_class_chain('XCUIElementTypeWindow/XCUIElementTypeButton[3]')
    
            Returns:
                `appium.webdriver.webelement.WebElement`
    
            :rtype: `appium.webdriver.webelement.WebElement`
            """
            return self.find_element(by=MobileBy.IOS_CLASS_CHAIN, value=class_chain_string)
    

    以上这个多定位方式。根据我的经验,推荐使用:

    Android:AndroidUIAutomator > className = id = AccessibilityId > xpath。

    iOS:iOSNsPredicateString > className = AccessibilityId> xpath。

    总结:

    1. 选择定位方式的判断:

    如果显示在界面的文本唯一或是第一个出现:使用accessibility

    如果class唯一或是第一个出现:className

    ID或class不方便定位,控件属性有明确的匹配规则:iOSNsPredicate

    如果有工具可以直接给出准确的xpath:xpath

    实在不行就用坐标吧 driver.tap([(30, 95), [30, 98]], 500)

    1. 如果控件的属性visible是false的话,请使用控件坐标并获取中心点用tap点击,直接点击控件会失败

    自动处理系统权限弹框

    autoAcceptAlerts:True 低版本有效
    autoAcceptAlerts 如果它们弹出,将自动接受所有iOS警报。这包括隐私访问权限警报(例如,位置,联系人,照片)。默认为false。true 要么 false
    autoDismissAlerts 如果所有iOS警报弹出,将自动将其关闭。这包括隐私访问权限警报(例如,位置,联系人,照片)。默认为false。true 要么 false

    def get_desired_capabilities():
       desired_caps = {
           #平台名称
           'platformName': 'iOS',
           #平台版本
           'platformVersion': '11.3',
           #设备名称
           'deviceName': 'iPhone 8 Plus',
           #app 的地址
           'app': '/Users/tanzhiwu/Desktop/appium自动化测试/UTengineFrameworkTest.app',
           #bundleid 如果没有填 app 地址,填了这个 id 就会直接运行已安装的 app
           'bundleId': 'com.ut.pc.UTengineFrameworkTest',
           #超时时间
           'newCommandTimeout': 60,
           #自动化测试平台
           'automationName': 'Appium',
           #是否不重新安装启动
           'noReset': True
           #自动处理系统权限弹框
           #`autoAcceptAlerts`:True 低版本有效
       }
       return desired_caps
    
    
    #def setUp(self):
           #获取我们设定的 capabilities,通知 appium Server 创建相应的对话
           #desired_caps = desired_capabilities.get_desired_capabilities()
           #获取 Server 的地址
           #uri          = desired_capabilities.get_uri()
           #创建会话,得到 driver 对象,driver 对象封装了所有的设备操作
           #self.driver = webdriver.Remote(uri,desired_caps)
           #设定等待时间,系统函数,在这个时间内会持续获取,超时会失败
           #self.driver.implicitly_wait(10)
           #处理系统权限弹框(新版本方法)
           #self.driver.switch_to.alter.accept()
    import time, os
    from appium import webdriver
    from appium.webdriver.common.touch_action import TouchAction
    
    driver = webdriver.Remote(command_executor='http://127.0.0.1:4723/wd/hub',
                             desired_capabilities={
                                 'bundleId': 'com.53zaixian.young',
                                 'platformName': 'iOS',
                                 'platformVersion': '11.2.5',
                                 'deviceName': 'iPhone7 test',
                                 "automationName": "XCUITest",
                                 "noReset": True,   #是否不重新安装启动
                                 "udid": "c527ea59a43aabf64f0c088f87b071fdefda7192"
                             })
    
    
    #此方法判断用户是否已登陆
    def check_shouye():
    
       print('开始判断....')
       try:
           shouye=driver.find_element_by_accessibility_id("tab_dashboard")
       except Exception as e:
           print('no canceBtn')
    
           print('点击账号登录')
           driver.find_element_by_accessibility_id("login_account").click()
           driver.implicitly_wait(5)
           #输入用户名
           driver.find_element_by_accessibility_id("login_account_account_input").send_keys("1650@qq.com")
           #输入密码
           driver.find_element_by_accessibility_id("login_account_password_input").send_keys("123456")
           #点击登录
           driver.find_element_by_accessibility_id("login_account_login").click()
    
           print('登录后')
           time.sleep(5)
           driver.find_element_by_accessibility_id("tab_dashboard")
           #点击新建
           TouchAction(driver).tap(x=329, y=571).perform()
           #点击新建文档
           TouchAction(driver).tap(x=63, y=438).perform()
           #定位标题
           TouchAction(driver).tap(x=40, y=120).perform()
    
    
       else:
           print('已经登陆了!')
    
    check_shouye()
    

    xpath定位方式在 XCUITest 底层原生不支持,由 appium 额外支持的,定位速度很慢,而且有时候定位不到元素的情况存在。综上所述,在 iOS 的 UI 自动化中,使用原生支持的iOSNsPredicateString定位方式是最好,支持也是最好的。

    相关文章

      网友评论

          本文标题:iOS 元素定位总结

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