简介
许仙小时候最喜欢吃又甜又软的汤圆了, 一次一颗汤圆落入西湖, 被一条小白蛇衔走了. 十几年后, 一位身着白衣, 有青衣丫鬟相伴的美丽女子与许仙相识了, 她叫白娘子. 白娘子聪明又善良, 两个人很快走到了一起. 靠着自己的力量, 他们过上了幸福的生活. 一天, 僧人法海找到许仙, 警告说白娘子是一条修行千年的蛇精, 许仙不信. 到了端午节, 勉强喝下了雄黄酒的白娘子现了原形, 许仙被吓得昏死过去. 原来白娘子真的是之前吃下许仙汤圆的小蛇. 白娘子辛苦救回了许仙的性命, 但之后法海却以保护许仙的名义将他囚禁起来, 白娘子与小青召集虾兵蟹将, 要逼法海放出许仙. 突然一座宝塔从天而降, 把白娘子镇在了塔下...... 想必小伙伴和童鞋们都听过, 或者是看过这个故事, 是多么的痴情感人, 尤其是千年等一回的歌曲是一个经典音乐. 好了废话还是少说, 进入今天的主题 -- 元素等待
前边介绍了 App 页面元素的识别定位, 操作等技术, 可能你会觉得掌握这两项技术就可以实施 App 自动化了, 答案基本是这样的, 毕竟元素定位和操作是核心技术. 但是, 在某些场景, 脚本的运行并非预期那样, 如, 要操作的元素用常规方法无法识别, 元素可以识别但在脚本运行时却未如期而至等. 为了解决这些疑难杂症, 接下来内容将会介绍处理这些问题的通用方法.
在本节, 主要介绍元素等待的使用方法和场景, 该方法是开发稳定, 高容错性自动化脚本的前提.
思考
在自动化过程中, 元素出现受网络环境, 设备性能等多种因素影响. 因此元素加载的时间可能不一致, 从而会导致元素无法定位超时报错, 但是实际上元素是正常加载了的, 只是出现时间晚一点而已. 那么如何解决这个问题呢?
实际测试过程中, 比如点击一个控件需要启动一个新 activiy 界面, 或需要加载弹框, 或请求网络加载数据成功后刷新界面, 此时需要等待一段时间, 新界面出现了才能继续执行 UI 操作, 否则还在加载中, 程序已开始执行新界面操作的代码, 脚本就会报错了.
元素等待作用
1. 设置元素等待可以更加灵活的制定等待定位元素的时间, 从而增强脚本的健壮性, 提高执行效率.
2. 元素等待是为了解决如下场景的问题: 脚本执行时, 脚本的执行速度和页面元素的加载速度未必一致, 也就是说, 可能出现脚本已经运行到某个元素, 但该元素尚未加载到页面, 此时脚本会因无法定位到该元素而导致执行失败. 元素等待本质是为了解决时序上不匹配的问题.
元素等待类型
类型 | 特点 | 举例 |
强制等待 | 设置固定的等待时间
| from time import sleep # 强制等待 5 秒 < br ztid="74" ow="0" oh="0"> sleep(5)
|
隐式等待 | 针对全部元素设置的等待时间
| driver.implicitly_wait(5)
|
显示等待 | 针对某个元素来设置的等待时间
| from selenium.webdriver.support.ui import WebDriverWait WebDriverWait(driver, timeout, poll_frequency=0.5, ignored_exceptions=None)
|
强制等待
这种方法的等待, 就相当于白素贞到西湖去等待许仙去, 不管许仙是否出现, 都要痴情地从白天等到晚上. 说白了这种就是白素贞站在西湖那里一动不动地死等许仙出现. 纯粹一个傻子!!!
设置固定的等待时间, 使用 sleep()方法即可实现
sleep(): 设置固定休眠时间. python 的 time 包提供了休眠方法 sleep() , 导入 time 包后就可以使用 sleep()进行脚本的执行过程进行休眠.
- from time import sleep
- #强制等待 5 秒
- sleep(5)
隐式等待
隐式等待是针对全部元素设置的等待时间
这种方法的等待, 就相当于白素贞到西湖去等待许仙去, 白素贞到了西湖先看看许仙在不在, 一看在, 白素贞完了再看看小青妹妹来没来, 等小青这个电灯泡来了, 再去和许仙汇合.
- #implicitly_wait(): 是 webdirver 提供的一个超时等待. 隐的等待一个元素被发现, 或一个命令完成. 如果超出了设置时间的则抛出异常.
- #implicitly_wait(): 隐式等待
- #当使用了隐士等待执行测试的时候, 如果 WebDriver 没有在 DOM 中找到元素, 将继续等待, 超出设定时间后则抛出找不到元素的异常
- #换句话说, 当查找元素或元素并没有立即出现的时候, 隐式等待将等待一段时间再查找 DOM, 默认的时间是 0
- #一旦设置了隐式等待, 则它存在整个 WebDriver 对象实例的声明周期中, 隐式的等到会让一个正常响应的应用的测试变慢,
- #它将会在寻找每个元素的时候都进行等待, 这样会增加整个测试执行的时间.
- #implicitly_wait()方法比 sleep() 更加智能, 后者只能选择一个固定的时间的等待, 前者可以在一个时间范围内智能的等待.
- driver.implicitly_wait(20)
显式等待
显式等待是针对某个元素来设置的等待时间.
这种方法的等待, 就相当于白素贞到西湖去等待许仙去, 白素贞到了西湖先看看许仙在不在, 一看不在, 白素贞自己先去做个头发; 过一个小时了, 白素贞回来到西湖再去看许仙在不在, 一看还是不在, 再去买件衣服去; 过一个小时了, 白素贞回来到西湖再去看许仙在不在, 一看仍然不在, 再去买个包包去; 过一个小时了, 白素贞回来到西湖再去看许仙在不在, 一看还是不在, 白素贞郁闷了, 出去喝个小酒去; 过了一小时了...... 就这么来来回回的折腾的等许仙. 这个白素贞通过修炼进化变得聪明了.
WebDriverWait(): 同样也是 webdirver 提供的方法. 在设置时间内, 默认每隔一段时间检测一次当前. 页面元素是否存在, 如果超过设置时间检测不到则抛出异常.
方法 WebDriverWait 格式参数如下:
- '''详细格式如下:
- WebDriverWait(driver, timeout, poll_frequency=0.5, ignored_exceptions=None)
- driver - WebDriver 的驱动程序(Ie, Firefox, Chrome 或远程)
- timeout - 最长超时时间, 默认以秒为单位
- poll_frequency - 休眠时间的间隔 (步长) 时间, 默认为 0.5 秒
- ignored_exceptions - 超时后的异常信息, 默认情况下抛 NoSuchElementException 异常.
- WebDriverWai()一般由 until()或 until_not()方法配合使用, 下面是 until()和 until_not()方法的说明.
- until(method, message='')
- 调用该方法提供的驱动程序作为一个参数, 直到返回值不为 False.
- until_not(method, message='')
- 调用该方法提供的驱动程序作为一个参数, 直到返回值为 False.
- lambda
- lambda 提供了一个运行时动态创建函数的方法.'''
- from selenium.webdriver.support.ui import WebDriverWait
- WebDriverWait(driver,10).until(lambda x:x.find_element_by_id("elementID"))
其中, 三种等待方法的作用和区别, 如下:
强制等待, 也就是常说的死等待, 使用 time 模块提供的 sleep 方法, 脚本在等待 sleep(x) x 秒后才执行, 此时脚本也许出现了无效等待, 即元素已经出现, 可以继续操作, 但因指定的时间未到, 脚本无法执行, 因而, 在实际 Web UI 开发中应杜绝 sleep 等待;
显式等待, WebDriver 提供的针对元素级别的, 灵活, 智能的等待方法, 通过配合 until(),until_not(),ExpectedCondition 等条件的使用, 默认每 500ms 检查一次条件状态, 可以及时将脚本从等待中唤醒, 避免无效等待, 在实际应用中推荐使用该方法.
该等待的调用方法如下:
WebDriverWait(driver, 超时时长, 调用频率, 忽略异常).until(可执行方法, 超时时返回的信息)
隐式等待, WebDriver 提供的针对 driver 级别的适用整个生命周期的等待方法, 该等待是全局设置, 因而只需在实例化 driver 后设置一次即可. 从等待作用上看, 是可以满足需要的, 但是考虑到实际应用场景, driver 要等待的元素和脚本要操作的元素未必相同, 也就是说, 脚本要操作的元素已经出现, 但因为设置了全局等待, driver 也会继续等待页面上其他无关元素, 直至整个页面加载完毕. 因而, 与显式等待相比, 可能出现无效等待的情况.
等待方法实战举例
1. 强制等待方法应用实例
- # coding=utf-8
- # 1. 先设置编码, utf-8 可支持中英文, 如上, 一般放在第一行
- # 2. 注释: 包括记录创建时间, 创建人, 项目名称.
- '''
- Created on 2019-7-26
- @author: 北京 - 宏哥 QQ 交流群: 707699217
- Project: 学习和使用 appium 自动化测试 - 元素等待
- '''
- # 3. 导入模块
- from appium import webdriver
- import time
- desired_caps = {}
- desired_caps['platformName'] = 'Android' #Android 的 apk 还是 iOS 的 ipa
- desired_caps['platformVersion'] = '8.0' #Android 系统的版本号
- desired_caps['deviceName'] = '127.0.0.1:62001' #手机设备名称, 通过 adb devices 查看
- desired_caps['appPackage'] = 'com.taobao.taobao' #apk 的包名
- desired_caps['appActivity'] = 'com.taobao.tao.welcome.Welcome' #apk 的 launcherActivity
- desired_caps['unicodeKeyboard'] = True #使用 unicodeKeyboard 的编码方式来发送字符串
- desired_caps['resetKeyboard'] = True #将键盘给隐藏起来
- driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps) #启动服务器地址, 后面跟的是手机信息
- # 休眠五秒等待页面加载完成
- time.sleep(5) #强制等待 5s, 不管等待的元素是否出现, 都要等 5s
- driver.find_element_by_id("com.taobao.taobao:id/home_searchedit").click()
- time.sleep(3) #演示效果
- driver.find_element_by_id("com.taobao.taobao:id/searchEdit").click()
- driver.find_element_by_id("com.taobao.taobao:id/searchEdit").send_keys(u"北京 - 宏哥")
- driver.quit()
2. 显示等待方法应用实例
- # coding=utf-8
- # 1. 先设置编码, utf-8 可支持中英文, 如上, 一般放在第一行
- # 2. 注释: 包括记录创建时间, 创建人, 项目名称.
- '''
- Created on 2019-7-26
- @author: 北京 - 宏哥 QQ 交流群: 707699217
- Project: 学习和使用 appium 自动化测试 - 元素等待
- '''
- # 3. 导入模块
- from appium import webdriver
- from selenium.webdriver.support.ui import WebDriverWait
- import time
- desired_caps = {}
- desired_caps['platformName'] = 'Android' #Android 的 apk 还是 iOS 的 ipa
- desired_caps['platformVersion'] = '8.0' #Android 系统的版本号
- desired_caps['deviceName'] = '127.0.0.1:62001' #手机设备名称, 通过 adb devices 查看
- desired_caps['appPackage'] = 'com.taobao.taobao' #apk 的包名
- desired_caps['appActivity'] = 'com.taobao.tao.welcome.Welcome' #apk 的 launcherActivity
- desired_caps['unicodeKeyboard'] = True #使用 unicodeKeyboard 的编码方式来发送字符串
- desired_caps['resetKeyboard'] = True #将键盘给隐藏起来
- driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps) #启动服务器地址, 后面跟的是手机信息
- try:
- # 显示等待(等待特定元素出现)
- WebDriverWait(driver, 3).until(lambda x: x.find_element_by_id('com.taobao.taobao:id/home_searchedit'))
- driver.find_element_by_id("com.taobao.taobao:id/home_searchedit").click()
- time.sleep(3) # 演示效果
- driver.find_element_by_id("com.taobao.taobao:id/searchEdit").click()
- driver.find_element_by_id("com.taobao.taobao:id/searchEdit").send_keys(u"北京 - 宏哥")
- finally:
- driver.quit()
3. 隐式等待方法应用实例
- # coding=utf-8
- # 1. 先设置编码, utf-8 可支持中英文, 如上, 一般放在第一行
- # 2. 注释: 包括记录创建时间, 创建人, 项目名称.
- '''
- Created on 2019-7-26
- @author: 北京 - 宏哥 QQ 交流群: 707699217
- Project: 学习和使用 appium 自动化测试 - 元素等待
- '''
- # 3. 导入模块
- from appium import webdriver
- from selenium.webdriver.support.ui import WebDriverWait
- import time
- desired_caps = {}
- desired_caps['platformName'] = 'Android' #Android 的 apk 还是 iOS 的 ipa
- desired_caps['platformVersion'] = '8.0' #Android 系统的版本号
- desired_caps['deviceName'] = '127.0.0.1:62001' #手机设备名称, 通过 adb devices 查看
- desired_caps['appPackage'] = 'com.taobao.taobao' #apk 的包名
- desired_caps['appActivity'] = 'com.taobao.tao.welcome.Welcome' #apk 的 launcherActivity
- desired_caps['unicodeKeyboard'] = True #使用 unicodeKeyboard 的编码方式来发送字符串
- desired_caps['resetKeyboard'] = True #将键盘给隐藏起来
- driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps) #启动服务器地址, 后面跟的是手机信息
- # 隐式等待(等待所有元素)
- driver.implicitly_wait(3) #隐式等待, 最长 3s
- driver.find_element_by_id("com.taobao.taobao:id/home_searchedit").click()
- time.sleep(3) #演示效果
- driver.find_element_by_id("com.taobao.taobao:id/searchEdit").click()
- driver.find_element_by_id("com.taobao.taobao:id/searchEdit").send_keys(u"北京 - 宏哥")
- driver.quit()
小结
1. 本节主要介绍 appium 自动化中三种元素等待方法, 并讲解了各自的优缺点, 实际开发中推荐使用显示等待, 最后, 为了便于理解和应用, 针对每种等待方法, 编写了对应的脚本.
2. 强制等待的方法, 在 debug 时候很有用, 不过建议慎用这种方法, 因为太死板, 严重影响程序执行速度!
3. 以上三种等待方法, 在具体的场景中需要根据情况选择合适的方法, 灵活运用...
4. 做过自动化的小伙伴们或者童鞋们, 在启动 App 的时候, 幸运的小伙伴和同学们都会中这个大奖: 如果直接做下一步点击操作, 经常会报错, 于是我们便会自然而然的想到上边介绍的三种方法, 会在启动完成的时候加 sleep 等方法. 那么问题来了, 宏哥问你这个 sleep 时间到底设置多少合适呢? 你不知道宏哥也不知道这个问题的答案, 如果设置长了, 就浪费时间, 设置短了, 就会找不到元素报错了. 过长过短都是个让你头疼的事, 那么有没有别的方法可以克服这个问题了. 当然有, 宏哥一般人都不告诉他, 大家都是二般人, 就分享给各位吧! 但是这个只是针对安卓手机的哦, 要记住了, iPhone 不适合的. 这个时候我们可以用 wait_activity 的语法, 等到你想点击的页面 activity 出现了, 再点击, 可以有效的节省时间.
wait_activity
(1)查看源码
- def wait_activity(self, activity, timeout, interval=1):
- """Wait for an activity: block until target activity presents
- or time out.
- This is an Android-only method.
- :Agrs:
- - activity - target activity
- - timeout - max wait time, in seconds
- - interval - sleep interval between retries, in seconds
- """
- try:
- WebDriverWait(self, timeout, interval).until(
- lambda d: d.current_activity == activity)
- return True
- except TimeoutException:
- return False
(2)解释说明:
- wait_activity(self, activity, timeout, interval=1):
等待指定的 activity 出现直到超时, interval 为扫描间隔 1 秒
即每隔几秒获取一次当前的 activity
Android 特有的
返回的 True 或 False
:Agrs:
- activity - 需等待的目标 activity
- timeout - 最大超时时间, 单位是 s
- interval - 循环查询时间
用法: driver.wait_activity('.activity.xxx',5,2)
获取 current_activity
(1)打开 App 后, 先 sleep10 秒, 等 App 完全启动完成进入主页面, 然后获取当前界面的 activity
- # coding=utf-8
- # 1. 先设置编码, utf-8 可支持中英文, 如上, 一般放在第一行
- # 2. 注释: 包括记录创建时间, 创建人, 项目名称.
- '''
- Created on 2019-7-26
- @author: 北京 - 宏哥 QQ 交流群: 707699217
- Project: 学习和使用 appium 自动化测试 - 元素等待
- '''
- # 3. 导入模块
- from appium import webdriver
- from time import sleep
- desired_caps = {
- 'platformName': 'Android',
- 'deviceName': '127.0.0.1:62001',
- 'platformVersion': '4.4.2',
- 'appPackage': 'com.baidu.yuedu',
- 'appActivity': 'com.baidu.yuedu.splash.SplashActivity'
- }
- driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
- sleep(10)
- # 获取当前界面 activity
- ac = driver.current_activity
- print(ac)
(2)运行结果:
等待 activity
(1)用 sleep 太浪费时间了, 并且不知道什么时候能启动完成, 所以尽量不用 sleep, 宏哥也不推荐使用. 因为这个确实是太 low 了.
(2)上一步已经获取当主页面的 activity 了, 那就可以用 wait_activity 等它出现了, 再做下一步的点击操作
(3)参考代码
- # coding=utf-8
- # 1. 先设置编码, utf-8 可支持中英文, 如上, 一般放在第一行
- # 2. 注释: 包括记录创建时间, 创建人, 项目名称.
- '''
- Created on 2019-7-26
- @author: 北京 - 宏哥 QQ 交流群: 707699217
- Project: 学习和使用 appium 自动化测试 - 元素等待
- '''
- # 3. 导入模块
- from appium import webdriver
- from time import sleep
- desired_caps = {
- 'platformName': 'Android',
- 'deviceName': '127.0.0.1:62001',
- 'platformVersion': '4.4.2',
- 'appPackage': 'com.baidu.yuedu',
- 'appActivity': 'com.baidu.yuedu.splash.SplashActivity'
- }
- driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
- # sleep(10) # 不用 sleep
- # 获取当前界面 activity
- ac = driver.current_activity
- print(ac)
- # 等主页面 activity 出现, 30 秒内
- driver.wait_activity(".base.ui.MainActivity", 30)
- # 点知道了
- driver.find_element_by_id("com.baidu.yuedu:id/positive").click()
5. 好了, 关于元素等待目前就说这么多!!!
您的肯定就是我进步的动力. 如果你感觉还不错, 就请鼓励一下吧! 记得点波 推荐 哦!!!(点击右边的小球即可, 胆子大的可以试一下 :))
个人公众号
微信群
来源: https://www.cnblogs.com/du-hong/p/11243741.html