最近在做IOS自动化测试,IOS的Appium环境都配置OK,执行起来真的慢,慢到怀疑人生,那么今天就来总结一下IOS定位方式和各个定位方式的速度排序。


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

ios_predicate >> accessibility_id >> class_name >>xpath

1、元素属性介绍

 

ios怎么审查元素 ios手机审查元素_iOS

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


2、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'")


3、accessibility_id

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


4、class_name

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


5、xpath

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

 

Appium使用WebDriverAgent之后,新增了一种定位方法iOSNsPredicate,总结了一下使用方法:

 

driver.findElementByIosNsPredicate("name = 'head new'"); // 等于
 driver.findElementByIosNsPredicate("name LIKE '*new'");  // 模糊匹配
 driver.findElementByIosNsPredicate("name MATCHES '^$'"); // 正则表达式匹配
 driver.findElementsByIosNsPredicate("name CONTAINS '我的'"); // 包含
 driver.findElementsByIosNsPredicate("name BEGINSWITH '我的'"); // 以"我的"开始
 driver.findElementsByIosNsPredicate("name BEGINSWITH '我的' && name ENDSWITH '消息'"); // 以"我的"开始并且以"消息"结尾

 

其中属性名参照inspector的属性字段,关键字LIKE,MATCHES,CONTAINS,BEGINSWITH,ENDSWITH必须是大写,匹配的字符需要用单引号

官方参考地址:

https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/ios_predicate.md

 

最后给个建议:

1 选择定位方式的判断:

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

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

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

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

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

2 如果控件的属性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': 'chuxin.shimo.wendang.2014',
                              '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()