你真的了解appium吗?

背景:对于QA同学来说,appium应该都不陌生,作为市面上最流行的app自动化测试框架之一,凭借强大的扩展性、跨平台能力和活跃的社区,使得它成为了移动端自动化测试的首选。今天让我们一起重新了解下这个工具!

appium运行原理

appium有几个重要的部分组成,分别是appium client、web driver以及 appium server。Appium server,负责接受客户端请求并与移动设备进行通信。它使用WebDriver协议来与客户端进行通信,并使用移动设备的原生测试框架Ui automation2或者XCUITest来执行自动化测试。appium自动化app的所有指令都是基于W3C的web driver协议的。所以如果你认真看过appium的log的话,会发现每一个动作查找元素或者点击元素都是一次http请求。

图片

官方给我们提供的driver有UIautomator和XCUITest等,所以我们可以直接下载对应的driver同Android以及iOS平台进行通讯,如果是其他平台的话,比如webOS TV,官方没有提供相应的driver,那我们就要根据web driver协议自定义一份适合webOS 的driver来完成跟webOS应用通讯的目的。对于自定义driver有兴趣的可以了解下web driver协议以及base driver。

从appium日志角度了解相关的操作逻辑

  @classmethoddef start(cls):caps = {"platformName": "Android","appium:deviceName": "liangzai_test_simulator","appium:appPackage": "tv.danmaku.bili","appium:appActivity": ".MainActivityV2","appium:newCommandTimeout": 6000,"appium:automationName": "UiAutomator2","appium:ensureWebviewsHavePages": True,"appium:nativeWebScreenshot": True,"appium:connectHardwareKeyboard": True}cls.driver = webdriver.Remote("http://127.0.0.1:4723", caps)

图片

建立连接是通过post请求,产生一个session,内容是capability中的相关信息。

图片

连接建立成功后系统会寻找ADB工具,理论上每一个Android的SDK都会带有一个adb工具,这里会全部list出来然后选择一个进行使用。首先会去判断simulator上是否已经存在appium.settings,没有则安装。然后检查io.appium.uiautomator2.server,没有则安装。

图片

ADB工具负责连接simulator查看其中是否存在目标app,没有找到则尝试使用adb install app路径 命令安装。如果在连接的capability中没有设置安装app的选项,appium会认为该应用已经被安装在模拟器上并寻找,找到后如果没有设置NoReset为True的话,adb会使用am和pm命令停止正在运行的app并且清除已有数据。

图片

打开app会使用ADB的shell am start命令,打开会进入设置好的main activity页面。接下来进行的操作就会转移到Uiautomator2进行。

driver.implicitly_wait(10)
el1 = driver.find_element(by=AppiumBy.ID, value="tv.danmaku.bili:id/agree").click()
el2 = driver.find_element(by=AppiumBy.ID, value="tv.danmaku.bili:id/tv_skip").click()
el4 = driver.find_element(by=AppiumBy.ID, value="tv.danmaku.bili:id/search_text").click()
el5 = driver.find_element(by=AppiumBy.ACCESSIBILITY_ID, value="Search query")
el5.send_keys("Demon Slayer: Kimetsu No Yaiba")
el6 = driver.find_element(by=AppiumBy.ID, value="tv.danmaku.bili:id/action_search")
el6.click()

图片

隐式等待实际上是一个timeout的请求,每个请求都会带有一个session id,–>代表client发出的请求,<–代表server返回的结果。那么find_element和click操作的时候是怎么执行的呢?

图片

这里使用的是by ID的操作,我们可以通过日志发现其实是有个转化的过程的,UIautomator并不是直接使用ID = XX进行查找的,而是由 [“id”,“tv.danmaku.bili:id/agree”,“380fc8dc-7d2e-4426-b326-0a4b97c37cf8”]的形式转成了{“strategy”:“id”,“selector”:“tv.danmaku.bili:id/agree”,“context”:“”,“multiple”:false}这样的形式。

●strategy: 定位策略,这里是id,表示使用元素的id属性来定位元素。

●selector: 元素定位器,这里是 “tv.danmaku.bili:id/agree”,表示要定位的元素的id属性值为"tv.danmaku.bili:id/agree"。

●context: 上下文环境,这里为空,表示在当前页面中查找元素。

●multiple: 是否允许定位多个元素,这里为false,表示只查找一个符合条件的元素。如果使用find_elements,这里就是True。

图片

按照这样的策略在当前页面寻找元素,如果找不到但是又因为设置了隐式等待没有超时的情况下,appium会重试再次寻找该元素直到超时。找到元素后会返回对应的ID值,也就是这里的 element/00000000-0000-005e-ffff-ffff00000011。接下来对这个元素进行点击操作的时候也是继续使用这个id:POST /element/00000000-0000-005e-ffff-ffff00000011/click] 执行click操作。

通过上面的分析我们可以直观的了解appium client的各种操作其实都是一次次的HTTP请求,每次操作都映射一个对应的请求,这也是appium支持各种不同类型编程语言的重要原因。

JSONWP协议

JSONWP的全称是Mobile JSON Wire Protocol,appium client所有的库都是基于此建立的。所以我们直接使用协议,按照协议的请求方式发送curl命令,一样可以完成自动化的操作。它本质是web driver协议的扩展协议,所以有些说法是appium基于web driver协议的也没问题。由于移动端的自动化测试不完全和web测试一样,移动端不仅有native应用,还有hybrid以及纯H5的应用,所以原有的web driver协议不能满足需求,于是便有了JSONWP协议。以下是一些比较常用的内容:

协议增加了Capabilities,如:automationName、platformName、platformVersion、deviceName等,增加了定位策略,如accessibility id;

增加了Page Source,所以我们可以使用pagesource方法获取当前页面所有的元素,这对于我们判断某元素是否存在很有帮助,同时我们也可以通过打印page source 进行debug。

为了同时支持native和webview两种不同格式的元素寻找,还增加了context内容,所以我们在进行hybrid测试的时候可以用过切换上下文的方式使用appium和selenium的不同寻址方式操作元素。

appium源码分析

这一部分主要是给想要看源代码的人提供一点思路,在日志部分我们知道了appium使用了很多adb命令,如果你更有好奇心想要知道它是怎么操作这些adb命令的?或者好奇find_element 是怎么实现元素查找的?那么你就需要通过查看源代码来解答你的疑问。

appium的源代码分成两个部分,appium仓库内的代码是将底层内容整合在一起的一个体现,可以通过appium -> lib - > main.js开始一步一步的了解这个过程。如果想了解更加底层的东西,可以通过package.json中的dependency来看。

举个例子:如果想看Android的底层实现,就在appium的package.json中寻找相应的Android依赖,(注意:在appium 2.x中已经将driver分离出去了,也就是需要单独npm install driver,依赖的driver不会写在package.json中,使用这种方法请切换1.x版本分支)可以找到appium-uiautomator2-driver,再进到appium-uiautomator2-driver的package.json 中我们可以找到appium-uiautomator2-server,它是一个java编写的应用并且没有依赖其他的库,所以这就是最下面的实现了。将它clone 下来后我们就能在里面找到uiautomator2操作app的各种命令。比如find_element是这么实现的:

protected AppiumResponse safeHandle(IHttpRequest request) throws UiObjectNotFoundException {FindElementModel model = toModel(request, FindElementModel.class);final String method = model.strategy;final String selector = model.selector;final String contextId = isBlank(model.context) ? null : model.context;if (contextId == null) {Logger.info(String.format("method: '%s', selector: '%s'", method, selector));} else {Logger.info(String.format("method: '%s', selector: '%s', contextId: '%s'",method, selector, contextId));}ElementsCache elementsCache = AppiumUIA2Driver.getInstance().getSessionOrThrow().getElementsCache();final By by = ElementsLookupStrategy.ofName(method).toNativeSelector(selector);final AccessibleUiObject element = contextId == null? findElement(by): findElement(by, elementsCache.get(contextId));if (element == null) {throw new ElementNotFoundException();}AndroidElement androidElement = elementsCache.add(element, true, by, contextId);return new AppiumResponse(getSessionId(request), androidElement.toModel());}

这段代码我们可以发现,其实是接受了一个IHttpRequest request然后进行解析,解析的内容有strategy,selector,context,这就解释了上面日志中为什么对find请求的内容做了一次转化的原因。如果元素没有找到,那就会抛出ElementNotFoundException异常。

同样的方式也适用于iOS,相关的内容可以追溯到一个名叫WebDriverAgent的仓库中,他是一个object-c编写的应用。在里面有XCUITest对于ios底层相关操作的实现逻辑。

知道这些后就可以尝试对appium进行二次封装然后在本地使用自己定制化的appium啦!下次有时间再写二次封装的相关内容。(下次一定🧐)最后希望大家看到这里能有所收获,对appium有新的了解,如果有更多想法也欢迎一起探讨!卷起来🤓

感谢每一个认真阅读我文章的人!!!

作为一位过来人也是希望大家少走一些弯路,如果你不想再体验一次学习时找不到资料,没人解答问题,坚持几天便放弃的感受的话,在这里我给大家分享一些自动化测试的学习资源,希望能给你前进的路上带来帮助。

软件测试面试文档

我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

 

          视频文档获取方式:
这份文档和视频资料,对于想从事【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!以上均可以分享,点下方小卡片即可自行领取

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

关于jmeter设置为中文问题之后无法保存设置的若干问题

1、jemeter如何设置中文模式 Options--->Choose Language--->Chinese(Simplifies), 如此设置后就可显示中文模式(缺点&#xff1a;下次打开还是英文)&#xff1b;如下图所示&#xff1a; 操作完成之后&#xff1a; 但是下次重启之后依旧是英文&#xff1b; 2、在jmeter.…

k8s jenkins 2.421动态创建slave

k8s jenkins 动态创建slave 简述使用jenkins动态slave的优势&#xff1a;制作jenkins-slave从节点jenkins-slave-latest:v1配置jenkins动态slave配置 Pod Template配置容器模板挂载卷 测试 简述 持续构建与发布是我们日常工作中必不可少的一个步骤&#xff0c;目前大多公司都采…

机器视觉基础系列四—简单了解背景建模算法

机器视觉基础系列四—简单了解背景建模算法 首先我们应该了解的是背景建模的定义是什么&#xff1f;又有哪些应用场景呢&#xff1f; 背景建模是指通过分析视频序列中的像素值变化情况&#xff0c;从中提取出静态背景部分&#xff0c;并将其用于目标检测、运动跟踪等计算机视觉…

从0开始部署优化虚拟机

一&#xff0c;vm workstation 安装 CentOS-7 忽略 二、查看虚拟机IP ip address 得到 192.168.196.128/24 宿主机进行Ping测试 C:\Users\Administrator>ping 192.168.196.128正在 Ping 192.168.196.128 具有 32 字节的数据: 来自 192.168.196.128 的回复: 字节32 时间…

怎么向新闻媒体发稿?携手谛道文化,轻松实现新闻媒体发稿

在纷繁复杂的信息时代&#xff0c;企业与个人若欲崭露头角&#xff0c;一套行之有效的发稿策略无疑是突破重围的利剑。企业或个人该怎么向新闻媒体发稿呢&#xff1f;谛道文化新闻媒体发稿机构&#xff0c;在软文发布、新闻发布及媒体投放等方面具有卓越策略&#xff0c;无疑为…

I\O进程线程(Day30)

一、学习内容 多线程基础 1> 线程是任务器调度的基本单位&#xff0c;是进程的一个执行单元 2> 一个进程中可以包含多个线程&#xff0c;但是至少要包含一个线程称为主线程 3> 一个进程中的多个线程共享进程的资源&#xff0c;不会为线程再 单独分配内存空间 4> 线…

如何启动hive

检查mysql是否启动 通过Navicat测试mysql是否可以连接 找打hive配置文件所在目录 检查连接mysql的账号密码是否正确,如果不正确就要修改为正确的 初始化hive元数据存储的库:schematool -dbType <database_type> -initSchema 检查mysql中是否创建hive数据库,这里看到hive数…

WebGl 使用缓冲区对象绘制多个点

缓冲区对象是WebGL系统中为一块内存区域&#xff0c;可以一次性地向缓冲区对象中填充大量的顶点数据&#xff0c;然后将这些数据保存在其中&#xff0c;供顶点着色器使用。 1.类型化数组类型 在 webgl 中&#xff0c;需要处理大量的相同类型数据&#xff0c;所以引入类型化数组…

机器学习学习笔记-20241018

继续跟着小土堆去学习机器学习 文章目录 Flatten1. Flatten 的作用2. 何时使用 Flatten3. PyTorch 中的 Flatten Sequentia优化器模型的保存与加载模型的完整训练 Flatten 在神经网络中&#xff0c;Flatten 操作是将高维的输入&#xff08;如二维图像或三维特征图&#xff09…

LabVIEW提高开发效率技巧----减少UI更新频率

在LabVIEW开发中&#xff0c;图形化用户界面&#xff08;UI&#xff09;的更新频率对程序的响应速度有着显著影响。频繁的UI更新会占用大量资源&#xff0c;导致系统性能下降。本文将详细介绍如何通过减少UI更新频率来提升LabVIEW程序的运行效率&#xff0c;从多个角度进行分析…

Jenkins入门(二):流水线方式部署多模块Springboot项目

目录 一、环境准备 1. 搭建配置Jenkins (在上一篇基础上进行) 2. 安装mysql 3. 安装redis 4. 配置docker-componse 5. 启动docker-componse 二、脚本准备 1. Jenkinsfile 2. deploy.sh 3. Dockerfile 三、Jenkins流水线配置 新增版本号参数 流水线选择代码里面的Je…

游戏逆向基础-找释放技能CALL

思路&#xff1a;通过send断点然后对send的data参数下写入断点找到游戏里面的技能或者攻击call 进入游戏先选好一个怪物&#xff08;之所以要先选好是因为选怪也会断&#xff0c;如果直接左键打怪的话就会断几次&#xff09; 断下来后对参数下硬件写入断点 硬件断点断下来后先…

Java | Leetcode Java题解之第475题供暖器

题目&#xff1a; 题解&#xff1a; class Solution {public int findRadius(int[] houses, int[] heaters) {Arrays.sort(houses);Arrays.sort(heaters);int ans 0;for (int i 0, j 0; i < houses.length; i) {int curDistance Math.abs(houses[i] - heaters[j]);whil…

【工具篇】MLU运行XInference部署手册

文章目录 前言一、平台环境准备二、代码下载三、安装部署1.正常pip 安装 四、运行结果展示1.如果界面404或没有东西请这样做2.运行效果 前言 Xorbits Inference&#xff08;Xinference&#xff09;是一个功能强大、用途广泛的库&#xff0c;旨在为语言、语音识别和多模态模型提…

Python | Leetcode Python题解之第478题在圆内随机生成点

题目&#xff1a; 题解&#xff1a; class Solution:def __init__(self, radius: float, x_center: float, y_center: float):self.xc x_centerself.yc y_centerself.r radiusdef randPoint(self) -> List[float]:u, theta random.random(), random.random() * 2 * mat…

js简单基础笔记

一 . js特点 1. Js是一门解释型语言&#xff0c;不用编译&#xff0c;而是直接执行 2. js是一门动态语言&#xff0c;其中的任何内容都是不确定的 3. 语法结构和Java&#xff0c;c都很像 4. ​ js是一门面向对象的语言 5.js严格区分大小写 二 . js使用 1…

【AI知识】距离度量和相似性度量的常见算法

本文介绍一些AI中常见的距离度量和相似性度量算法&#xff1a; 1. 欧几里得距离&#xff08;Euclidean Distance&#xff09; 欧几里得距离是最常见的距离度量方法&#xff0c;用来计算两个向量之间的“直线距离”&#xff0c;也被成为L2范数。 公式如下&#xff0c;其中 x…

6、ES6

文章目录 一.关于ES6二.关于变量声明let声明变量const 声明常量 三.变量的解构赋值四.字符串的扩展五.函数的扩展函数默认参数rest参数箭头函数(函数的新写法) 六.数组的扩展七.对象的扩展语法上的简化对象的解构赋值 八.Symbol&#xff1a;新的数据类型(类似于字符串)独一无二…

学习中,师傅b站泷羽sec——xss挖掘过程

某职业技术学院网站xss挖掘&#xff1a; 资产归纳 例如&#xff1a;先把功能点都看一遍&#xff0c;大部分都是文章 根据信息搜集第一课学习到一般主站的防御力是比较强的&#xff0c;出现漏洞的点不是对新手不友好。 在资产验证过程中还是把主站看了一遍 没有发现有攻击的机会…

未来人工智能的发展对就业市场的影响 人工智能在生活中的相关

人工智能&#xff08;Artificial Intelligence&#xff09;&#xff0c;英文缩写为AI.是新一轮科技革命和产业变革的重要驱动力量&#xff0c; 是研究、开发用于模拟、延伸和扩展人的智能的理论、方法、技术及应用系统的一门新的技术科学. 人工智能的发展对就业市场的影响主要…