Appium 三种等待机制
三种等待机制
1. 等待方式
使用 Appium Desktop 录制的用例直接使用会出现一个现象,页面还没加载出来用例已经报错NoSuchElementError元素未找到。当页面未完全渲染出来就去页面查找,找不到元素就会抛出这样一个错误,如何避免这种情况的发生,可以在操作的步骤中间加入等待元素出现的操作。
例如,打开 APP 后在首页要去点击一个元素,很快就报错了,从 Appium 日志中能发现错误日志
Matched W3C error code 'no such element' to NoSuchElementError Encountered internal error running command: NoSuchElementError: An element could not be located on the page \ using the given search parameters.
上面的错误就是由于页面没有完全加载出来就去查找元素,可以在页面中添加等待操作,比如:time.sleep(5)。强制地等待 5 秒后,能够点到需要的元素。然而,这个时间却很难把握,太长影响运行的速度,太短影响通过率。下面介绍几种更灵活的方式去动态的等待页面元素的出现。在开展appium自动化测试的时候,常用的等待方式有以下三种:
- 强制等待 time.sleep(5)
- 隐式等待 driver.implicitly_wait(15)
- 显式等待 WebDriverWait(driver, 10)
下面详细介绍一下三种等待方式的具体应用场景。
2. 强制等待
强制等待设置了固定休眠时间。python 的 time 包提供了休眠方法 sleep( )方法 ,导入time包后就可以使用 sleep( )执行过程进行休眠。代码如下:
import time time.sleep(5)
强制等待,如果在执行某一行代码之前添加一个强制等待,那么就必须等待设定的秒数后才能开始执行后面的代码。由于手机的性能问题,网络问题等原因导致页面加载速度不确定。打开app的时候有的手机需要2秒能加载完成,有些手机可能需要10秒甚至更长时间,此时设置多少合理变成了难题,所以一般测试过程中不建议使用强制等待的方式。
3. 隐式等待
implicitly_wait( ) 是 webdirver 提供的一个超时等待。在规定的时间之内去动态的等待元素出现。如果设置了隐式等待时长为10秒,当调用driver.find_element()方法时会在10秒之内每隔0.5秒查找一次元素,如果第2秒就找到了元素,就继续执行后面的测试代码。如果超出了设置时间10秒都没有找到元素则抛出异常。一旦设置了隐式等待,则它存在整个 WebDriver 对象实例的声明周期中,直到调用driver.quit()整个session 消毁才会失效。implicitly_wait( )方法比 sleep( ) 更加智能,后者只能选择一个固定的时间内等待,前者可以在一个时间范围内智能的等待。代码示范:
self.driver = webdriver.Remote(server, desired_caps) self.driver.implicitly_wait(15)
此时我们从appium的log中能发现以下的情况,注意下面的 xx 和 xxy 是对 ID 的简写:
[W3C] Matched W3C error code 'no such element' to NoSuchElementError [BaseDriver] Waited for 1495 ms so far [WD Proxy] Matched '/element' to command name 'findElement' …… [W3C] Matched W3C error code 'no such element' to NoSuchElementError [BaseDriver] Waited for 2707 ms so far [WD Proxy] Matched '/element' to command name 'findElement' …… [HTTP] <-- POST /wd/hub/session/xx/element 200 6653 ms - 137 [HTTP] [HTTP] --> POST /wd/hub/session/xx/element/xxy/click [HTTP] {"id":"xxy"}
从日志上可以看出来,appium在进行元素查找的时候失败后不会直接抛出来异常停止脚本,而是每过一段时间去找一次元素,例证所示的在 6.7 秒左右等到了元素的返回,此时结束等待,去执行点击操作。
4. 显式等待机制
显示等待是针对页面某个特定的元素设置的等待时间,在设置时间内,默认每隔一段时间检测一次当前页面某个元素是否存在。
如果在规定的时间内找到了元素,则直接执行(即找到元素就执行相关操作),如果超过设置时间检测不到则抛出异常。默认检测频率为0.5s,默认抛出异常为:NoSuchElementException。显示等待必须在每个需要等待的元素前面进行声明。
显式等待可以等待动态加载的ajax元素,比隐式等待更加灵活的定位元素。显示等待用到的两个类:WebDriverWait 和 expected_conditions。
5. WebDriverWait类解析
WebDriverWait 用法:
WebDriverWait( driver,timeout,poll_frequency=0.5,ignored_exceptions=None)
参数解析:
-
driver:WebDriver实例对象
-
timeout: 最长等待时间,单位秒
-
poll_frequency: 检测的间隔步长,默认为0.5s
-
ignored_exceptions: 执行过程中忽略的异常对象,默认只忽略TimeoutException异常类
WebDriverWait通常与until和util_not结合使用。
-
until(method, message='')
在规定时间内,每隔一段时间调用一下method方法,直到期返回值不为False,如果超时抛出带有message的TimeoutException异常信息 -
until_not(method, message='')
与until( )方法相反,表示在规定时间内,每隔一段时间调用一下method方法,直到期返回值为False,如果超时抛出带有message的TimeoutException异常信息
6. expected_conditions类解析
expected_conditions类是selenium的一个模块,其中包含一系列可用于判断的条件。可以用来判断页面的元素是否可见,是否可点击等。
导入
需要先导入这个模块,导入代码如下:
from selenium.webdriver.support import expected_conditions
常用方法
1.presence_of_element_located(locator)方法,用来判断元素是否被加到了DOM树里,并不代表该元素一定可见,用法如下:
WebDriverWait().until( expected_conditions.presence_of_element_located(元素对象))
2.visibility_of_element_located(locator)方法,用来判断某个元素是否可见(可见代表元素非隐藏,并且元素的宽和高都不等于0,用法如下:
WebDriverWait().until( expected_conditions.visibility_of_element_located(元素定位符))
3.element_to_be_clickable(locator)方法,判断某元素是否可见并能点击,用法如下:
WebDriverWait().until( expected_conditions.element_to_be_clickable((By.ID, "kw")))
7. 案例
使用“雪球”应用,打开雪球 APP,点击页面上的搜索输入框输入“alibaba”,然后在搜索联想出来的列表里面点击“阿里巴巴”,选择股票分类,获取股票类型为“09988”的股票价格,最后验证价格大于 170。
代码片断如下:
def test_wait(self): # 点击搜索输入框 self.driver.find_element_by_id( "com.xueqiu.android:id/tv_search").click() # 输入 “alibaba” self.driver.find_element_by_id( "com.xueqiu.android:id/search_input_text" ).send_keys("alibaba") # 点击“阿里巴巴” self.driver.find_element_by_xpath("//*[@text='阿里巴巴']").click() # 点击“股票” self.driver.find_element_by_xpath( "//*[contains(@resource-id,'title_container')]//*[@text='股票']" ).click() # 获取股票价格 locator = (MobileBy.XPATH, "//*[@text='09988']/../../..\ //*[@resource-id='com.xueqiu.android:id/current_price'") ele = WebDriverWait(self.driver,10)\ .until(expected_conditions.element_to_be_clickable(locator)) print(ele.text) current_price = float(ele.text) expect_price = 170 # 判断价格大于 expect_price assert current_price > expect_price
上面的代码使用了显式等待等待价格这个元素,通过expected_conditions.element_to_be_clickable这个方法来判断元素可以被点击,中间添加了10秒的等待时间,在10秒之内每隔0.5秒查找一次元素,如果找到了这个元素,就继续向下执行,如果没找到就报TimeoutException信息。显式等待可以在某个元素上灵活的添加等待时长,尤其是文件上传,或者资源文件下载的场景中,可以添加显式等待,提高脚本的稳定性。
小结
掌握了 Appium 三种等待机制后,是时候来学习强⼤的 PageObject 模式了。
<p> 专刊包含了10+年经验测试架构师对测试职业发展的深度解读 帮助你掌握当下 BAT 流行的 App 自动化测试技术基础技能和工具使用;以及从入门到进阶的自动化测试实战经验,在面试中能够脱颖而出。 本专刊购买后即可解锁所有章节,故不可以退换哦~ </p> <p> <br /> </p> <p> <br /> </p>