Appium等待机制--强制等待、隐式等待、显式等待

news2025/3/14 13:41:45

书接上回,Appium高级操作--其他操作-CSDN博客文章浏览阅读182次,点赞6次,收藏7次。书接上回Appium高级操作--从源码角度解析--模拟复杂手势操作-CSDN博客。 https://blog.csdn.net/fantasy_4/article/details/146162851主要讲解了Appium的一些高级操作,比如基于ActionChain类的,操作系统API的方法等,便于解决比较复杂的场景下的手势模拟。不过在自动化的过程中,经常会出现寻找查找元素时间过长,等待时间设置不合理导致脚本执行时间过程,最终的结果就是自动化运行的速度不如'手工'操作。为了解决上述问题,本篇文章主要讲解一下Appium的等待机制

1.影响页面加载时长的因素

做UI自动化的同学可能多数都会遇到这样的问题,执行跳转页面后再去定位,经常会提示找不到元素,造成找不到元素的原因除了有元素定位本身的问题之外,还可能的原因是页面本身的加载时长过长,那影响页面加载时长的因素有哪些呢?

  • 移动端性能

市面上出现生产使用的移动端各不相同,不同的配制,不同的机型,不同的系统,甚至不同的操作系统版本,因此在这些设备上安装同一款软件就会产生不同的加载时长。如果调试脚本时使用的是一款配置较好的手机,而实际运行脚本的是另外的配置较差的手机,就会出现明明调试的时候没问题,正式运行就会出错。

  • 服务端性能

如果执行自动化的服务端还部署着其他服务,比如缺陷管理工具、代码管理工具等,这样服务端存在大量并发用户请求,就会造成自动化执行时会花费更多的时间才能相应。

  • 网络因素

如果被测试APP中的Web页面包含大量图片,或者请求中存在低劣无效的代码就会产生大量的数据请求,这是网络的稳定至关重要。

2.强制等待

所谓强制等待,就是在执行自动化的过程中加上一个强制的等待时间,等待时间结束后期望要跳转的页面能够加载完毕,如果没有那可能还是要调整时间。

通常使用Python time模块的time.sleep(s) 来实现

优点:调试代码时,能够便于我们观察脚本的执行情况

缺点:强制等待会导致执行脚本的时间不一致,设置的等待时间参差不齐,尤其是脚本很多时,就会造成脚本越执行越慢。

那么有没有一种更智能的等待方式呢?能够实现找到元素就立刻进行下一步操作,如果找不到元素就进行等待呢?

3.隐性等待

隐性等待就能够完美解决上面提出的问题。

Appium的隐性等待继承了Selenium的implicitly_wait()方法。

driver.implicitly_wait(5) # 隐性等待5s

优点:可以很智能判断是否需要执行相应等待时长,一旦设置就会实例化整个会话的生命周期

缺点:会减缓测试速度(尤其是在需要查找某个元素不存在时的用例,会平白浪费时间等待查找该元素是不是存在),而且会干扰显性等待,不建议使用隐形等待和显性等待混用

4.显性等待

显性等待能够更精细化的定制一些执行条件,等到条件满足会后在进行下一步操作。

Appium并没有引入Selenium的WebDriverWait类,因此要使用显性等待,只能从Selenium中引入,主要由以下两部分实现显性等待

1)Selenium中的WebDriver类:定义超时时间、轮询频率等

2)Expected_conditions模块:提供一些预期条件作为测试脚本进行后续操作的判断依据

  • 显性等待整体语法结构

WebdriverWait(dirver, 超时时间,轮询频率, 忽略异常).until(可执行方法,超时后返回的信息)

上面代码的含义:每隔一段时间,一定频次,就会调用可执行方法,直到方法返回True,如果超时则返回超时后的信息。

注意until中的可执行方法必须是可以调用的,即这个对象一定有__call__()方法

  • WebDriverWait类源码分析

def __init__(
 self,
 driver: D,
 timeout: float,
 poll_frequency: float = POLL_FREQUENCY,
 ignored_exceptions: Optional[WaitExcTypes] = None,
):
 """Constructor, takes a WebDriver instance and timeout in seconds.
​
 Attributes:
 ----------
 driver
        - Instance of WebDriver (Ie, Firefox, Chrome or Remote) or
        a WebElement
​
    timeout
        - Number of seconds before timing out
​
    poll_frequency
        - Sleep interval between calls
        - By default, it is 0.5 second.
​
    ignored_exceptions
        - Iterable structure of exception classes ignored during calls.
        - By default, it contains NoSuchElementException only.

WebDriverWait类创建对象可以传入4个参数:

  • driver:WebDriver实例化-必传

  • timeout:超时时间-必传

  • poll_frequency:轮询频率-非必传

  • ignored_exceptions:可忽略异常-非必传

WebDriverWait类提供两个方法until()until_not(),两个方法传参相同

  • method:可以调用方法-必传,

  • str: 异常信息-非必传

两个方法的含义不同:

 untiluntil_not
等待逻辑等待条件变为 True等待条件变为 False
适用场景等待元素出现或满足特定条件。等待元素消失或不满足特定条件。
异常处理如果条件未变为 True,抛出 TimeoutException如果条件未变为 False,抛出 TimeoutException
返回值返回满足条件的对象(如元素)无返回值(仅等待条件变为 False

(使用的Selenium是配套Appium-Python-Client一起下载的,版本是 4.29.0,其中until_not的方法注释(定义部分)有错误)如下图

  • Expected_conditions模块

Expected_conditions模块是selenium提供的各种预期条件,Expected_conditions有多种方法,黑体字相对比较常用

方法描述
title_is(title: str)判断页面的title和预期title是否一致,一直则返回True,否则返回False
title_contains(title: str)判断页面的title是否包含预期title是否一致,大小写敏感一直则返回True,否则返回False
presence_of_element_located(locator: Tuple[str, str])用于检查某个元素是否存在于DOM中,但不一定可见,一旦找到元素则返回WebElement
presence_of_all_elements_located(locator: Tuple[str, str])用于检查所有元素是否存在,如果存在返回所有匹配的元素的列表,否则报错
url_matches(pattern: str)检查当前driver的url是否包含字符串,包含返回True,不包含返回False
url_to_be(url: str)检查当前driver的url与预期值是否完全匹配,匹配返回True,否则返回False
url_changes(url: str)检查当前url和预期值是否一致,不一致返回True,一直返回False
url_contains(url: str)检查当前driver的url是否包含字符串,包含返回True,不包含返回False
visibility_of(element: WebElement)参数是WebElement,判断元素是否在当前页面的DOM中并可见,若是返回True,否则返回False
visibility_of_element_located(locator: Tuple[str, str] )参数是locator,判断元素是否在当前页面的DOM中并可见,若是返回True,否则返回False
visibility_of_any_elements_located(locator: Tuple[str, str])至少能定位到一个可见元素,是返回列表 否则报错
visibility_of_all_elements_located(locator: Tuple[str, str] )找到所有符合条件的可见元素,是返回列表 否则报错
invisibility_of_element_located(locator: Union[WebElement, Tuple[str, str]] )判断不可见元素是否存在
invisibility_of_element(element: Union[WebElement, Tuple[str, str]] )判断元素是都不可见
staleness_of(element: WebElement)判断刷新后,元素是否仍然在DOM中,如果在返回False,否则返回True
frame_to_be_available_and_switch_to_it(locator: Union[Tuple[str, str], str])判断frame_locator是否存在,存在则跳转到对应frame并返回True,否则返回False
text_to_be_present_in_element(locator: Tuple[str, str], text_: str)判断text是否出现在元素中
text_to_be_present_in_element_value(locator: Tuple[str, str], text_: str )判断text是否出现在元素的value属性中
text_to_be_present_in_element_attribute(locator: Tuple[str, str], attribute: str, text: str )判断text是否出现在元素的属性中
element_to_be_clickable(mark: Union[WebElement, Tuple[str, str]] )检查元素是否可见并可以被单击并且单击
element_to_be_selected(element: WebElement)入参为WebElement,被定位的元素是否是被选中的,返回布尔值
element_located_to_be_selected(locator: Tuple[str, str])入参为locator,被定位的元素是否是被选中的,返回布尔值
element_selection_state_to_be(element: WebElement, is_selected: bool)检查给定元素是否是被选中的
element_located_selection_state_to_be(locator: Tuple[str, str], is_selected: bool )查找元素并检查指定的选择状态是否处于该状态的期望,返回布尔值
new_window_is_opened(current_handles: List[str])传入当前窗口的句柄,判断是否有新窗口打开,返回布尔值
number_of_windows_to_be(num_windows: int)判断窗口数量是否符合预期
alert_is_present()判断是否有alert,如果有,切换到alert,否则返回False
  • 代码演示

    from appium import webdriver
    from appium.options.android import UiAutomator2Options
    from appium.webdriver.common.appiumby import AppiumBy
    from selenium.webdriver.support.wait import WebDriverWait
    from selenium.webdriver.support import expected_conditions
    ​
    desired_caps = {
        "platformName": "Android",
        "deviceName": "XXXXXXXXXXXXX",
        "appPackage": "com.sankuai.movie",
        "appActivity": "com.sankuai.movie.MovieMainActivity",
        "automationName": "UiAutomator2"
    }
    ​
    print("Desired Capabilities: ", desired_caps)
    ​
    driver = webdriver.Remote("http://localhost:4723", options=UiAutomator2Options().load_capabilities(desired_caps))
    ​
    ​
    try:
        agree_id = "com.sankuai.movie:id/cyf"
        ele1 = WebDriverWait(driver, 10).until(expected_conditions.presence_of_element_located((AppiumBy.ID, agree_id)))
        ele1.click()
        my_id = 'com.sankuai.movie:id/b50'
        ele2 = WebDriverWait(driver, 10).until(expected_conditions.invisibility_of_element_located((AppiumBy.ID, my_id)))
        # WebDriverWait(driver, 10).until_not()
        ele2.click()
        
        ele4 = WebDriverWait(driver,10).until(expected_conditions.element_to_be_clickable((AppiumBy.ID, 'com.sankuai.movie:id/b50')))
        ele4.click()
    ​
    except Exception as e:
        raise e
    ​
    finally:
        # 关闭 Appium 会话
        driver.quit()
    ​
  • 自定义等待条件

就是在expected_conditions模块不满足个需求的情况下,可以使用lambda表达式来自定义等待条件。

from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions
​
ele3 = WebDriverWait(driver, 10).until(lambda driver: driver.find_elements(AppiumBy.ID, 'com.sankuai.movie:id/b50'))
ele3.click()

5.总结三种等待区别

 强制等待隐性等待显性等待
实现方式time.sleep(3)driver.implicitly_wait(5)Webdriver类+expected_conditions模块
灵活程度不管是否找元素,必须等待响应时间找到元素则不等待,否则等待在固定之间
生命周期当前行整个会话每个条件需要单独设置
使用场景脚本调试页面加载时间相对固定的全局等待场景,不建议跟显性等待混用动态页面或需要等待特定条件的复杂场景,建议多使用

下一章介可能会讲解一些关于自动化框架搭建相关内容,可以期待一下哦~

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2314898.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机视觉cv2入门之图像的读取,显示,与保存

在计算机视觉领域,Python的cv2库是一个不可或缺的工具,它提供了丰富的图像处理功能。作为OpenCV的Python接口,cv2使得图像处理的实现变得简单而高效。 示例图片 目录 opencv获取方式 图像基本知识 颜色空间 RGB HSV 图像格式 BMP格式 …

【QT】事件系统入门——QEvent 基础与示例

一、事件介绍 事件是 应用程序内部或者外部产生的事情或者动作的统称 在 Qt 中使用一个对象来表示一个事件。所有的 Qt 事件均继承于抽象类 QEvent。事件是由系统或者 Qt 平台本身在不同的时刻发出的。当用户按下鼠标、敲下键盘,或者是窗口需要重新绘制的时候&…

5-27 临摹大师-IP-Adapter

前言: 前一节我们主要介绍ControlNet中如何对黑白照片进行上色 主要介绍ControlNet中的IP-Adapter。这个也是一种类似的风格借鉴,类似Reference的能力。 当然IP-Adapter有两点或许可以吸引我们,一个是国人腾讯公司制作的。另一个在速度和效…

Spring MVC面试题(一)

1.什么是Spring MVC? 全称为Model View Controller,Spring MVC是Spring的一个模块,基于MVC架构模式的一个框架 2.Spring MVC优点? 1.可用各种视图技术,不仅限于JSP 2.支持各种请求资源映射策略 3. Spring MVC工作原…

Unity开发的抖音小游戏接入抖音开放平台中的流量主(抖音小游戏接入广告)

前言:作者在进行小游戏审核版本的过程中,碰到了下列问题,所以对这个抖音小游戏接入广告研究了下。 还有就是作者的TTSDK版本号是6.2.6,使用的Unity版本是Unity2022.3.29f1,最好和作者的两个版本号保持一致,因为我发现TTSDK旧版的很多函数在新版中就已经无法正常使用了,必…

统一 Elastic 向量数据库与 LLM 功能,实现智能查询

作者:来自 Elastic Sunile Manjee 利用 LLM 功能进行查询解析,并使用 Elasticsearch 搜索模板,将复杂的用户请求转换为结构化的、基于模式的搜索,从而实现高精度查询结果。 想象一下,你在搜索“距离 Belongil Beach 25…

[操作系统] 学校课程关于“静态优先级抢占式调度“作业

今天我们来分享两道题目哈, 学校弄得题目. T1: 静态优先级, 抢占式(1为高优先级) 图解: 以下是静态优先级抢占式调度的解题过程和结果: 解题思路: 优先级规则: 数值越小优先级越高。新进程到达时,若其优先级高于当前运行进程&…

【SpringBoot】MD5加盐算法的详解

目录 一、什么是加盐算法 二、如何实现加盐算法 2.1 加盐算法代码实现 2.2 注册页面中进行密码加盐 2.3 登录页面进行加盐的解密 2.4 注册和登录 一、什么是加盐算法 加盐算法是一种用于增强密码安全性的技术。这种技术通过在密码存储过程中添加一个随机生成的盐值&…

累计完工数量达到了xxxx超过了最大可完工数量xxxx

之前解决过一次,没有记录下来,不记得发生什么事情。又浪费几个小时去分析问题。这次的经历有点痛苦,碰上多表关连数据的勾稽。分析是河南用户的非法操作造成的。没有领料记录入不了库,跨月了。财务要求删单处理。删单之后&#xf…

飞鸟与鱼不同路

看,好美的太阳。 正是因为有人看才会觉得美,若无人问津,美又从何而来。 嘿嘿,今天提出辞去综合教研室主任一职,不想在这个管理上废时间啦~ 把时间用来考试.........用来做自己的事情,花在自己的身上&…

若依RuoYi-Cloud-Plus微服务版(完整版)前后端部署

一.目标 在浏览器上成功登录进入 二.源码下载 后端源码:前往Gitee下载页面(https://gitee.com/dromara/RuoYi-Cloud-Plus)下载解压到工作目录。 前端源码: 前往Gitee下载页面(https://gitee.com/JavaLionLi/plus-ui)下载解压到工作目录。 文档地址&a…

【redis】list类型:基本命令(下)

文章目录 LLENLREMLTRIMLSET阻塞版本命令BLPOP 和 BRPOP区别使用方式 命令小结内部编码 LLEN 获取 list 的长度 语法: LLEN key时间复杂度: O ( 1 ) O(1) O(1)返回值: list 长度 LREM 删除 count 个 key 中的元素 语法: LREM…

【数据挖掘】知识蒸馏(Knowledge Distillation, KD)

1. 概念 知识蒸馏(Knowledge Distillation, KD)是一种模型压缩和知识迁移技术,旨在将大型复杂模型(称为教师模型)中的知识传递给一个较小的模型(称为学生模型),以减少计算成本&…

VSCode 搭建C++编程环境 2025新版图文安装教程(100%搭建成功,VSCode安装+C++环境搭建+运行测试+背景图设置)

名人说:博观而约取,厚积而薄发。——苏轼《稼说送张琥》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 目录 一、VScode下载及安装二、安装 MinGW-w64 工具链三、Windows环境变量配置四、检查 M…

Ubuntu24.04 LTS 版本 Linux 系统在线和离线安装 Docker 和 Docker compose

一、更换软件源并更新系统 在 Ubuntu 24.04 LTS 中,系统引入了全新的软件源配置格式。现在的源配置文件内容更加结构化且清晰,主要包含了软件类型 (Types)、源地址 (URIs)、版本代号 (Suites) 以及组件 (Components) 等信息。 # cat /etc/apt/sources.li…

MTK Android12 最近历史任务 最左侧的清除历史任务改到页面底部

Android最近历史任务页面 -清除所有- 功能按钮放到底部 文章目录 需求需求原因 修改的核心文件实现方案最近历史任务基本UI结构了解代码实现思路实现方案RecentsViewTaskOverlayFactory在overview_actions_containerOverviewActionsView 实际效果 总结 需求 最近历史任务重&am…

TCP协议支持全双工原因TCP发送接收数据是生产者消费者模型

一、TCP支持全双工的原因 TCP协议支持全双工,即使用TCP协议进行通信时,服务端和客户端可以同时进行数据的发送和接收,互不干扰,实现同时双向传输数据。 这是因为使用TCP协议通信时,读写套接字的文件描述符既用来发送…

文件操作2

7. ⽂件读取结束的判定 7.1 被错误使用的 feof 牢记:在文件读取过程中,不能用 feof 函数的返回值直接来判断文件的是否结束。 feof 的作用是:当文件读取结束的时候,判断读取结束的原因是否是:遇到文件尾结束。 1. …

《又是二叉树?递归与回溯的经典应用》

“ 我喜欢晴天,你恰好是最好的太阳” 226.翻转二叉树 力扣题目链接(opens new window) 翻转一棵二叉树。 这道题我们可以通过递归法解决,我们只要递归的把每一个节点的左右孩子反转一下就能解决了。 代码如下: var invertTree function(ro…

Qt/C++音视频开发82-系统音量值获取和设置/音量大小/静音

一、前言 在音视频开发中,音量的控制分两块,一个是控制播放器本身的音量,绝大部分场景都是需要控制这个,这个不会影响系统音量的设置。还有一种场景是需要控制系统的音量,因为播放器本身的音量是在系统音量的基础上控…