Appium的工作原理终于搞清楚了

目录

1. Appium简介

1.1 Appium的理念

1.2 Appium 的设计

1.3 Appium 的概念

2. Appium原理架构

3. appium的工作流程

4. Appium-Uiautomator2-Server

4.1 Appium-Uiautomator2-Server简介

4.2 appium-uiautomator2-server运行原理

4.3 bootstrap vs appium-uiautomator2-server 的区别

5. appium自动化脚本

5.1 环境准备

5.2 第一个自动化脚本

6. 写在最后


1. Appium简介

官方文档描述如下:

Appium is an open source test automation framework for use with native, hybrid and mobile web apps.
It drives iOS, Android, and Windows apps using the WebDriver protocol.

Appium 是一个开源工具,用于自动化 iOS 手机、 Android 手机和 Windows 桌面平台上的原生、移动 Web 和混合应用。「原生应用」指那些用 iOS、 Android 或者 Windows SDKs 编写的应用。「移动 Web 应用」是用移动端浏览器访问的应用( Appium 支持 iOS 上的 Safari 、Chrome 和 Android 上的内置浏览器)。「混合应用」是指带有一个webview的包装器——用来和 Web 内容交互的原生控件。类似于 Apache Cordova 或 Phonegap 项目,创建一个混合应用使得用 Web 技术开发然后打包进原生包装器创建一个混合应用变得容易了。

重要的是,Appium 是跨平台的:它允许你用同样的 API 针对多平台(iOS、Android、Windows)测试,做到在 iOS、Android 和 Windows 测试套件之间复用代码。请参见 Appium 支持的平台

1.1 Appium的理念

Appium 旨在满足移动端自动化需求的理念,概述为以下四个原则:

  1. 你不应该为了自动化而重新编译你的应用或以任何方式修改它。
  2. 你不应该被限制在特定的语言或框架上来编写运行测试。
  3. 移动端自动化框架不应该在自动化接口方面重造轮子。
  4. 移动端自动化框架应该开源,在精神、实践以及名义上都该如此。

1.2 Appium 的设计

那么 Appium 项目的架构是如何实现这些理念的呢?为了实现理念#1,Appium 使用了系统自带的自动化框架。这样不需要把 Appium 特定的或者第三方的代码编译进应用,这意味着测试使用的应用与最终发布的应用并无二致。Appium 使用以下系统自带的自动化框架:

为了实现理念#2,Appium 把这些系统本身提供的框架包装进一套 API —— WebDriver API 中。WebDriver(也叫「Selenium WebDriver」)规定了一个客户端-服务器协议(称为 JSON Wire Protocol),按照这种客户端-服务器架构,可以使用任何语言编写的客户端向服务器发送适当的 HTTP 请求。已经有为 各个流行编程语言编写的客户端 。这也意味着我们可以自由使用任何我们想用的编程语言;客户端程序库不过是一个简单的 HTTP 客户端,可以以任何方式混入代码。换句话说,Appium & WebDriver 客户端在技术上而言不是「测试框架」,而是「自动化程序库」。

Appium 以同样的方式实现理念#3:WebDriver 已经成为 Web 浏览器自动化事实上的标准,并且是一个 W3C 工作草案,何必在移动端做完全不同的尝试?Appium 通过附加额外的 API 方法 扩展协议,这些方法对移动自动化非常有用。

理念#4是明确已知的—— Appium 是开源的

1.3 Appium 的概念

客户端 / 服务端架构
Appium 的核心一个是暴露 REST API 的 WEB 服务器。它接受来自客户端的连接,监听命令并在移动设备上执行,答复 HTTP 响应来描述执行结果。实际上客户端 / 服务器架构给予了我们许多可能性:我们可以使用任何有 http 客户端 API 的语言编写我们的测试代码,不过选一个 Appium 客户端程序库 用起来更为容易。我们可以把服务器放在另一台机器上,而不是执行测试的机器。我们可以编写测试代码,并依靠类似 Sauce Labs 的云服务接收和解释命令。

会话(Session)
自动化始终在一个会话的上下文中执行,这些客户端程序库以各自的方式发起与服务器的会话,但最终都会发给服务器一个 POST /session 请求,请求中包含一个被称作「预期能力(Desired Capabilities)」的 JSON 对象。这时服务器就会开启这个自动化会话,并返回一个用于发送后续命令的会话 ID。

预期能力(Desired Capabilities)
预期能力(Desired Capabilities)是一些发送给 Appium 服务器的键值对集合(比如 map 或 hash),它告诉服务器我们想要启动什么类型的自动化会话。也有许多能力(Capabilities)可以修改服务器在自动化过程中行为。例如,我们可以将 platformName 能力设置为 iOS,以告诉 Appium 我们想要 iOS 会话,而不是 Android 或者 Windows 会话。或者我们也可以设置 safariAllowPopups 能力为 true ,确保我们在 Safari 自动化会话期间可以使用 JavaScript 打开新窗口。有关 Appium 能力的完整列表,请参阅 Capability官方完整文档

Appium 服务端
Appium 是一个用 Node.js 写的服务器。可以从源码构建安装或者从 NPM 直接安装:

$ npm install -g appium
$ appium

Appium Server功能是监听接口,接收client端发送的command,然后将command转为移动端能够识别的command,然后发送给移动设备进行操作,再等待移动设备返回来的操作结果,将操作结果发送给client端。 Appium server是可以放在client端,也可以放在云端。 Appium server 默认的端口号是4723,用于Appium server监听client端的发送来的请求。

Appium 客户端

一般来说就是运行代码的机器,即我们是用Java语言编写的代码,也可以用其他Selenium支持Python,ruby,C#等语言来编写,Appium提供的Appium-client API是Appium通过扩展Selenium的Webdriver协议而来的,我们编写代码的时只要实现Webdriver标准协议即可。

Appium Desktop
这有一个 Appium 服务器的图形界面封装可以下载,它适用于任何平台。它打包了 Appium 服务器运行需要的所有东西,所以你不需要为 Node 而烦恼。它们还提供一个 Inspector 使你可以查看应用程序的层级结构,这在写测试时可以派上用场。

2. Appium原理架构

                                                图2.1 Appium架构

                                                图2.2 Appium Android模型

                                                    图2.3 Appium ios模型

3. appium的工作流程

脚本请求 ——> 4723端口appium server ——> 解析参数给PC端4724端口 ——> 发送给设备4724端口 ——> 通过设备4724端口发给bootstrap.jar ——> Bootstrap.jar把命令发给uiautomator

1、Appium server开启4723端口,监听客户端的连接

首先我们要开启appium服务,即Appium server,默认监听4723端口。4723端口专门和脚本打交道,基于WebDriver协议。接下来脚本与appium server的通信实际上是一个HTTP request请求给appium server,在请求的body中,会以WebDriver Wire协议规定的JSON格式的字符串来告诉appium服务我们希望设备接下来做什么事情。

appium中的Json wire protocol继承自selenium的webdriver wire protocol,并进行了扩展,使得Json wire protocol能够控制不同的移动设备的行为。

2、Appium client发送测试设备信息(desired Capabilities)给Appium server,请求创建session

上面说到的是脚本请求对设备进行操作,但前提是,我们要对谁进行操作测试呢?这里就引入一个新名词:desired Capabilities。了解了上述之后,再去看脚本怎么将desired Capabilities传递给appium server就明白多了,脚本通过Json Wire Protocol协议以json格式发送测试设备信息给server端,测试设备信息被携带在Desired Capabilities中,这个东西实质上是一个key-value形式的对象,Desired Capabilities最重要的作用是告诉server本次测试的上下文。这次是要进行浏览器测试还是移动端测试?如果是移动端测试的话是android还是ios?如果android的话我们要测试哪个app?server的这些疑问Desired Capabilities都必须给予解答,否则server不买账,针对我们现在所说的安卓,它带来的影响就是无法完成app的启动。

3、Appium server创建session id并返回给client,作为客户端请求的唯一标识

那么,将测试设备信息告知之后,是不是就可以开始进行测试了呢?答案是:NO。这里又要引入一个名词:session。session就是一个会话,在webdriver/appium,你的所有工作永远都是在session start后才可以进行的。client 请求创建1个session,在该session中通过http向appium server发送请求,appium server解析请求,完成相应操作并返回response。

Session在计算机中,尤其是在网络应用中,称为“会话控制”。Session 对象存储特定用户会话所需的属性及配置信息,对应到这里其实就是desired Capabilities中的配置信息参数。脚本通过POST    /session这个URL,然后传入Desired Capabilities就可以开启session了,由于这是第一次请求创建session,所有并没有一个已创建的session id,所以appium server会调用android driver(appium升级到2.0.0后,原有的AppiumDriver函数变成抽象函数了,需更改为AndroidDriver)为client生成一个session并且生成一个与此session相关联的session id,这个 session id将被在本次响应中返回给客户端保存,当下次脚本发出操作请求时就会自带session id为唯一标识,代表所打开的设备,Appium server会按照此session id把这个session检索出来使用,脚本向appium server发送的请求即是存在于创建的session中的。

Session 的作用就是它在appium服务上保持设备的状态信息,供在任何时间进行访问,在多次的操作行为中,存储在 Session对象中的配置信息将不会丢失,而是在整个用户会话中一直存在下去,整个测试进程中设备与程序的联系不会断开,也不需要每次都发送带配置信息的请求,程序都知道对哪个设备进行测试操作。当测试结束后,需关闭webdriver,driver.quit()会关闭所有关联窗口和session,并且也会把进程也关闭。

4、开启设备上的bootstrap socket服务,绑定本机和boostrap通信的端口号4724用于设备通讯

创建session成功之前,就已将bootstrap.jar放入手机中,并开启设备上的基于appium bootstrap的socket服务,绑定本机和boostrap通信的端口号4724用于和Android设备通讯,默认监听4724端口,等待client的连接。

Appium server将脚本的请求解析后给到4724端口,通过设备的4724端口转发解析后的请求, 此时,对于socket服务来说,appium server就充当了client的角色,appium server通过4724端口主动去请求设备上的socket服务,即向socket服务发送请求,即bootstrap.jar,Bootstrap.jar再把Appium的命令转换成uiautomator的命令来让uiautomator进行处理。有请求就有返回,socket接收到请求后会做出响应,原路返回给脚本,然后脚本再进行下一次的请求。

网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。appium和手机的通信过程,主要是数据交换的一个过程,socket的作用是就是为了实现双向通信,它需要一对端口号,对应到这里就是4724,手机端的bootstrap就是socket-server端,appium server就是socket-client端。

关于socket的通信原理,先从服务器端说起。服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。

5、Appium server通过4723端口将监听到的Appium client指令,通过4724端口转发给中间件Bootstrap.jar

6、Bootstrap再通过调用UIautomator的命令来实现具体的command操作。

7、最后Bootstrap将执行的结果返回给Appium server。

4. Appium-Uiautomator2-Server

4.1 Appium-Uiautomator2-Server简介

官方文档描述如下:

  • appium-uiautomator2-server module is targeted to re implement appium-android-bootstrap's bootstrap module using Google's UIAutomator V2 API.

  • appium-android-bootstrap built on top of Google's UIAutomator v1 and Google's UIAutomator v1 API is broken and officially depreciated now.

  • Google UIAutomator v2 fixes most of the problems in v1. The most important difference is decoupling the upgrade process of the framework from the underlying Android OS.

Prerequisites: This module should support from Android 5.0 (API Level 20) and above

Usage: From Appium server it is requested by specifying the desired capability automationName as uiautomator2 when starting a session.

简单概括一下:

  • appium-uiautomator2-server模块是使用Google的uiautomator v2 api重新实现appium android bootstrap模块。在这之前,Appium通过appium-android-bootstrap实现与UIAutomator v1的交互
  • Google UIAutomatorv2修复了v1中的大部分问题。最重要的区别是将框架的升级过程与底层的Android操作系统分离
  • 先决条件:此模块应支持Android 5.0(API级别20)及以上版本
  • 用法:在启动会话时,通过将所需的功能automationName指定为uiautomator2

ps.:我们都知道appium只有在uiautomator2下可以实现对toast的识别,那是因为Google新增了AccessibilityService服务,重写该服务可以实现对Notification和Toast内容的捕捉。

4.2 appium-uiautomator2-server运行原理

通信模块使用了Netty Server,较之bootstrap使用的ServerSocket,Netty是一个高性能、异步驱动的NIO框架,占用内存少,性能更好。

1. 客户端通过传递desired capabilities给appium node server请求创建一个AndroidDriver session,appium server根据automationName去启动对应的driver,默认是appium-android-driver。

2. 若automationName设为UIAutomator2,appium会调用appium-uiautomator2-driver来创建session,同时将uiautomator2 server的两个apk安装到测试设备上

  • appium-uiautomator2-server-vX.X.X.apk,执行handlers
  • appium-uiautomator2-server-debug-androidTest.apk,只有一个test,用于启动server

3. 启动Netty Server并启动Netty server session,Netty server将继续监听设备上的请求并做出相应的响应,直到DELETE SESSION被调用

3. AppiumServlet ,负责将driver发过来的请求重定向到相应的Handler来处理和响应请求

4. Handler,调用UiAutomator V2去执行指定操作,操作的结果经AppiumResponse捕获

5. AppiumResponse,捕捉到的AppiumResponse将返回给appium

4.3 bootstrap vs appium-uiautomator2-server 的区别

官方文档描述如下:

Both bootstrap and appium-uiautomator2-server modules are responsible to implement handlers to interact with Android Native and Hybrid apps. Below points will describe more details about these modules and development stack.

Bootstrap:

  • Will be packaged as AppiumBootstrap**.jar** and injected into the device/emulator while executing the tests.
  • Contains ServerSocket, always up and running to process the requests given by appium-android-driver.
  • Uses Google UIAutomator v1 to perform the actions.

appium-uiautomator2-server:

  • Will be packaged as appium-uiautomator2-server-vX.X.X**.apk**(X.X.X specifies version) and installed into the device/emulator while executing the tests.
  • Contains Netty Server up and running to process the requests given by appium-uiautomator2-driver. Using Netty Server gives better performance and less memory consumption over using ServerSocket.
  • Uses Google UIAutomator v2 to perform the actions. UIAutomator v2 has fixes for most of the v1 bugs and architectural level changes.

bootstrap和appium-uiautomator2-server模块都负责实现处理程序,以便与Android原生应用程序和混合应用程序交互。下面几点将描述这些模块的更多开发细节。

Bootstrap:

  • 被打包为AppiumBootstrap**.jar**,并在执行测试时注入设备/模拟器。
  • 包含ServerSocket,总是启动并运行以处理appium-android-driver给出的请求。
  • 使用googleuiautomator v1执行操作。

appium-uiautomator2-server:

  • 被打包为appium-uiautomator2-server-vX.X.X**.apk**(X.X.X指定版本),并在执行测试时安装到设备/模拟器中。
  • 包含Netty Server,启动并运行以处理appium-uiautomator2-driver给出的请求。与使用ServerSocket相比,使用Netty Server可以提供更好的性能和更少的内存消耗。
  • 使用Google UIAutomator v2执行操作。UIAutomator v2包含了v1版本大部分bug的修复和架构级别的更改。

5. appium自动化脚本

本示例使用python语言。

5.1 环境准备

5.2 第一个自动化脚本

1. 安装完成后,启动Appium,host和port默认的即可,然后设置Android SDk和Java JDK

2. 然后点下边那个保存并重启的按钮,然后点第一个Start Server按钮,将会看到

3. 连接手机,打开开发者模式,USB线连接手机和电脑,并且在开发者选项当中,开启USB调试,测试是否连接成功,可执行命令adb devices,出现下图就证明手机和电脑连接成功。

4. 回到appium,点击Start Inspector Session,按如下配置Desired Capabilities

  • Automatic Server 本地AppiumServer服务
  • Custom Server:例如,如果要针对运行在网络中另一台计算机上的Appium服务器启动Inspector会话,这很有用。
  • Sauce Labs:如果您无法访问机器上的iOS模拟器,则可以利用Sauce Labs帐户在云中启动Appium会话。
  • TestObject:您还可以利用TestObject的真实设备云来进行真机测试。
  • headspin:使用远程设备来创建会话。

  • platformName :声明是ios还是Android系统
  • platformVersion: Android内核版本号,可通过命令adb shell getprop ro.build.version.release查看
  • deviceName :连接的设备名称,通过命令adb devices -l中model查看
  • appPackage:apk的包名
  • appActivity:apk的launcherActivity,通过命令adb shell dumpsys activity | findstr “mResume”查看(需先打开手机应用)

注意:Android 8.1之前应使用adb shell dumpsys activity | findstr “mFocus”

5. 运行Start Session,选择元素,右侧 Selected Element 区域有三个按钮

  • Tap:执行选中元素的点击事件
  • Send Keys:为文本框等对象传值
  • Clear:如果是文本输入元素,就清除文本

6. 录制脚本,录制生成的python代码如下:

el2 = driver.find_element_by_xpath("/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.RelativeLayout[1]/android.widget.LinearLayout[1]/android.view.ViewGroup/android.widget.LinearLayout/android.support.v4.view.ViewPager/android.widget.FrameLayout/android.widget.ViewSwitcher/android.widget.RelativeLayout/android.support.v7.widget.RecyclerView/android.widget.LinearLayout[3]/android.widget.LinearLayout/android.widget.RelativeLayout/android.widget.LinearLayout/android.widget.LinearLayout/android.widget.ImageView")
el2.click()

7. 在pycharm中建立项目将代码粘入,在运行之前,还需通过pip命令安装pip install Appium-Python-Client依赖包

# coding:utf-8

from appium import webdriver

desired_caps={}
# 所使用的平台
desired_caps['platformName']='Android'
# 所使用的手机的名字   可以通过 adb devices 获得
desired_caps['deviceName']='127.0.0.1:62001'
# ANDROID 的版本
desired_caps['platforVersion']='7.1.2'
# app 的路径
desired_caps['app']=r'D:\Downloads\gome_Gome.apk'
# app的包名
desired_caps['appPackage']='com.gome.eshopnew'
# app 加载页面
desired_caps['appActivity']='com.gome.ecmall.home.LaunchActivity'
# 设置每次是否清除数据
desired_caps['noReset']='True'
# 是否使用unicode键盘输入,在输入中文字符和unicode字符时设置为true
desired_caps['unicodeKeyboard']="True"
# 是否将键盘重置为初始状态,设置了unicodeKeyboard时,在测试完成后,设置为true,将键盘重置
desired_caps['resetKeyboard']="True"
# appium服务器的连接地址
driver=webdriver.Remote('http://localhost:4723/wd/hub',desired_caps)
driver.implicitly_wait(2)

el2 = driver.find_element_by_xpath("/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.RelativeLayout[1]/android.widget.LinearLayout[1]/android.view.ViewGroup/android.widget.LinearLayout/android.support.v4.view.ViewPager/android.widget.FrameLayout/android.widget.ViewSwitcher/android.widget.RelativeLayout/android.support.v7.widget.RecyclerView/android.widget.LinearLayout[3]/android.widget.LinearLayout/android.widget.RelativeLayout/android.widget.LinearLayout/android.widget.LinearLayout/android.widget.ImageView")
el2.click()

最后,记一个我在这些过程中遇到的问题(现已解决)

在Appium-desktop中运行Start Session时,出现

解决方法:在开发者模式下,打开usb调试功能和use模拟点击,两个都要打开,此时再重新运行,即可解决。

6. 写在最后

有很多人问,UI自动化应不应该投入,有没有前途。这个问题没有绝对的,要看项目的类型,总的来说针对相对比较稳定的项目,UI自动化真正的价值有两点:1是验证逻辑而非UI;2是代替大量UI重复操作。如果这个事情至上而下都是支持的,想做的,投入的方向没有错,价值认识正确,肯定是有积极的产出的。另外,UI自动化是测试生来无法回避的一种能力,可以不依赖他,但是你需要他。最后用网上的几句话作为文章的结尾:

UI自动化是一种能力,常常无法回避;

UI自动化会给人幻觉,要看清现实与价值;

UI自动化最适合一句话,喜欢是放肆,爱是克制。而克制是UI自动化能发挥作用的关键。

 有兴趣可以关注我的微信公众号“自动化测试全栈”,微信号:QAlife,学习更多自动化测试技术。

也可加入我们的自动化测试技术交流群,QQ群号码:301079813

主要探讨loadrunner/JMeter测试、Selenium/RobotFramework/Appium自动化测试、接口自动化测试,测试工具等测试技术,让我们来这里分享经验、交流技术、结交朋友、拓展视野、一起奋斗!

参考文章:

1.Appium工作原理

2.基于Appium、Python的自动化测试环境部署和实践

3.Appium 官方介绍

4.用实例告诉你,如何利用Appium实现移动终端UI自动化测试

5.了解appium自动化的工作原理(uiautomator)

6.Python+Appium 运行简单的 Demo,你需要理解 Appium 运行原理!

7.Appium-Uiautomator2-Server原理分析

  • 28
    点赞
  • 67
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

慕城南风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值