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>

全部评论

相关推荐

点赞 收藏 评论
分享
牛客网
牛客企业服务