Appium 原理解析
既然选择了 app 自动化测试要使用 appium 这款工具,那么这个工具的工作原理是怎么样的呢?我们接下来了解一下。
简介
Appium 的工作原理涉及到复杂的通信过程。因为 Appium 服务集成了多种技术,它依赖其他服务的支持才能实现对多平台的强大兼容性。通过深入分析原理,可以更好地理解和使用 Appium,并为使用者提供更全面的视角,从而获得更大的帮助。
总结来说,了解原理有这样的几个价值。Appium 的工作原理涉及到复杂的通信过程。因为 Appium 服务集成了多种技术,它依赖其他服务的支持才能实现对多平台的强大兼容性。通过深入分析原理,可以更好地理解和使用 Appium,并为使用者提供更全面的视角,从而获得更大的帮助。
应用价值
了解原理虽然是一个有点晦涩难懂的过程,但是会在以下几个方面对我们产生极大的帮助:
- 应对面试:在大厂的面试过程中,面试官是非常喜欢询问一些原理性的知识,以测试候选人的研究能力。
- 分析与解决问题能力:Appium 由于其架构复杂,所以在安装与使用过程中会存在一些问题,掌握原理可以更好的分析问题出现的原因,以及完成对应的解决方案。
- 二次开发与定制开发能力:了解原理与其设计之后,才可以根据 Appium 的设计进行插件的二次开发与定制。
- 提升架构能力:每学习一个新的框架与其设计原理,都可以更好的帮助我们提升设计模式与架构设计能力。
了解原理虽然是一个有点晦涩难懂的过程,但是会在以下几个方面对我们产生极大的帮助:第一个价值肯定就是为了应对面试。其实我们收到了很多学员反馈的面试题,只要简历上写了是做移动端自动化测试的同学,那在一些大厂面试的时候,面试官是特别喜欢问一些原理性的知识的。去测试候选人的一个研究能力。比如他会问你 selenium 的原理知不知道,appium 的原理知不知道,tcp 三次握手四次挥手是什么样的过程。第二个就是可以提升我们分析和解决问题的一个能力。appium 的整体架构其实是挺复杂的。不知道大家在安装 appium 的过程当中有没有发现这个特点,appium 安装的时候需要很多依赖环境。我们需要配置 java,配置 npm,要安装 appium server,要安装 inspector。大家可以发现有非常多的组件。这样也能看出来这个工具的整体设计是比较复杂的。这样的话,在安装过程中,中间某一个环节一旦出问题,大家就会觉得哎呀解决不了了,抓瞎了。所以了解原理其实可以帮助我们更好的去分析问题出现的原因。知道原理我就可以知道这个报错可以去哪里看,然后看出来少了什么东西,然后我们再去搜索,再去解决。尤其在刚一开始,有很多同学会觉得,这个报错出现了,我想搜索解决方案,都不知道应该用什么关键词搜索。第三点就是二次开发和定制开发的一个能力。appium 现在有一个 plugin,而且它支持非常多中 dirver。如果说后面你也想要给 appium 开发一个 driver,我们就需要具备一些二次开发和定制开发的能力。第四个价值就可以提升我们的架构能力。我们每去学习一个框架的设计原理和它的设计模式的时候,其实都是再从更高的层面去拔高我们对于一个知识的视野也维度。
原理分析
从上图可以了解到,Appium 的设计主要分为三个大模块,每个模块都有其清晰的职能,完全符合设计模式中的单一职责,这也是其可拓展性强的原因:
- Client 端:将与 Appium 的各种交互封装为可被调用的 API 或工具,如此一来使用者就可以通过 Inspector 或者 Java/Python/其他语言的 Appium 第三库对 Appium Server 进行调用。
- Server 端:起到了信息中转的作用。启动了一个 HTTP 服务,如此就可以接收Client 客户端的请求信息。除此之外,会将所有的控制命令,比如:Adb 命令,自动化的控制命令等其他命令转发到被测应用的移动端上面。
- 移动端:真正执行自动化测试的地方。
由以上的三个模块可知,为了实现良好的拓展性,其实 Appium 的设计相对是比较复杂的。
接下来我们就来分析一下它的原理。我们先来梳理一下,安装 appium 的过程当中,我们都需要安装哪些东西呢?appium 客户端、appium 服务端、移动端,这就是我们在安装过程中需要涉及到的东西。在 appium 服务端这里,其实也有好几种形态。比如有界面的这种叫做 Appium GUI Server,或者在命令行执行的这种 Appium 命令行 Server。不管是 GUI 的也好,还是命令行的也好,都是 Appium 的服务端的一种形态,都可以提供 Appium 服务。我们使用的时候,选择其中一种就可以。比如刚学习的时候,觉得有个 GUI 界面更加方便操作和理解,而且安装也很方便,那我们就可以先安装 GUI Server。如果是服务器上要配置 appium 环境,就只能选择 appium 命令行 Server 了。所以说,启动 Appium Server,就是在 4723 端口启动一个服务,这就是 Appium Server 的作用。这个服务启动起来之后,谁会来访问这个服务呢?是不是就是服务端前面的这个组件,也就是客户端会访问这个服务。客户端其实就是我们编写的自动化脚本,或者 Inspector,它会通过 发送 HTTP 请求来访问 Appium 服务,给它下发一些指令。为什么说 Inspector 也是一个客户端呢,我们可以来求证一下。打开 Inspector,可以看到上面有一些配置项。从这儿就能看出来,Inspector 是通过上面这些配置的地址来发起 HTTP 请求。请求发给谁呢?就是发给我们的 Appium Server 端。前一部分其实还好理解。我们接下来看看 appium 服务端是如何和移动端交互的,也就是 appium 服务是如何操控移动端上的被测 app 来完成指定的操作的。其实在 appium 服务端和移动端交互的过程中,使用了不止一种通信方式。下面我们以 Android 移动端为例来介绍一下。比如我们想要控制 Android 移动端去安装一些 apk,或者说删除 apk,杀掉 app 等等的操作,这种会采用 adb 来完成操作。除了 adb,可能要需要下发一些具体的操作 app 界面元素的指令,比如要进行点击操作,或者滑动操作,这些指令,adb 命令就没有办法去传达了。这个时候,appium 就有一个很巧妙的设计。当服务端收到客户端发来的请求之后,服务端会在本机的 820x 端口再启动一个服务,一般情况下会在 8200 端口启动,当然了有的时候可能是别的,这个不是完全固定的。那启动了这个服务又是怎么和移动端通信的呢?大家应该能注意到,我们在启动 appium 服务之后,会自动给我们往移动端去安装几个 apk。打开模拟器,查看 appium settings app所以其实 appium 服务在第一次启动的时候,就会直接在移动端安装用来完成自动化测试的 apk。这个 apk 会监听移动端的 6790 端口。那接下来,appium 服务会把 820x 端口的指令,转发到移动端的 6790 端口,让 appium 自动化测试的 apk 能获取到。所以移动端通过 6790 端口就能拿到所有的指令了。比如说,6790 端口接收到的操作指令是点击被测 app 上的某个按钮,那么 appium 自动化测试的 apk 接到指令,就会去操作被测 app 完成相应的点击操作了。这就是 appium 服务与移动端通信的过程。不过刚才的这个描述为了易于理解我们做了点简化。实际情况下,移动端安装的 appium 自动化测试相关 apk 有 3 个,每个 apk 起到的作用都不一样。其中会监听 6790 端口的 apk 是 appium server-apk。真实的操作被测 apk 的是 appium-server-test.apk。而 appium settings 则是会完成一些初始化的配置。它们之间的通信过程是这样的。appium server 第一次启动的时候,会先安装整个过程其实在 appium server 的日志当中都可以看到详细的过程。
日志分析过程
以上的原理与过程,可以通过日志很清楚的看到整个流转的流程。
以下日志由于篇幅原因,会做删减,只保留关键信息,具体的日志信息,可以在 Server 中进行获取。
# 电脑本地的环境检查
[Appium] Welcome to Appium v2.3.0
[Appium] AndroidUiautomator2Driver has been successfully loaded in 0.704s
# 启动4723服务,在电脑端
[Appium] http://127.0.0.1:4723/ (only accessible from the same host)
[Appium] http://172.16.3.146:4723/
# 发送HTTP请求,其中主要包含capabilities信息
[HTTP] --> POST /session
[HTTP] {"capabilities":...}
# 创建Session
[AppiumDriver@b535] Calling AppiumDriver.createSession() with args: ......
[AppiumDriver@b535] Event 'newSessionRequested' logged at 1703213142195 (10:45:42 GMT+0800 (北美中部标准时间))
# 检查 driver 的配置环境
[Appium] Attempting to find matching driver for automationName 'uiautomator2' and platformName 'Android'
[Appium] The 'uiautomator2' driver was installed and matched caps.
[Appium] Will require it at /Users/lixu/.appium/node_modules/appium-uiautomator2-driver
[AndroidUiautomator2Driver@e8c7] Creating session with W3C capabilities: {....}
# 检查ADB 环境,以及使用ADB的过程
[ADB] Found 1 'build-tools' folders under '/Users/lixu/Library/Android/sdk' (newest first):
[ADB] Using 'adb' from '/Users/lixu/Library/Android/sdk/platform-tools/adb'
[ADB] Running '/Users/lixu/Library/Android/sdk/platform-tools/adb -P 5037 start-server'
# Appium 相关依赖的apk - io.appium.settings
[AndroidDriver] Pushing settings apk to device...
[ADB] Getting package info for 'io.appium.settings'
[ADB] Running '/Users/lixu/Library/Android/sdk/platform-tools/adb -P 5037 -s emulator-5554 shell dumpsys package io.appium.settings'
# 端口映射,从本地端口的 8200 转发到 移动端的6790端口
[AndroidUiautomator2Driver@e8c7 (beaa697d)] Forwarding UiAutomator2 Server port 6790 to local port 8200
[ADB] Forwarding system: 8200 to device: 6790
[ADB] Running '/Users/lixu/Library/Android/sdk/platform-tools/adb -P 5037 -s emulator-5554 forward tcp:8200 tcp:6790'
# Appium 相关依赖的apk appium-uiautomator2-server-v5.12.16.apk 以及 appium-uiautomator2-server-debug-androidTest.apk
[AndroidUiautomator2Driver@e8c7 (beaa697d)] Server packages status: [{"wasSigned":true,"installState":"sameVersionInstalled","appPath":"/Users/lixu/.appium/node_modules/appium-uiautomator2-driver/node_modules/appium-uiautomator2-server/apks/appium-uiautomator2-server-v5.12.16.apk","appId":"io.appium.uiautomator2.server"},{"wasSigned":true,"installState":"sameVersionInstalled","appPath":"/Users/lixu/.appium/node_modules/appium-uiautomator2-driver/node_modules/appium-uiautomator2-server/apks/appium-uiautomator2-server-debug-androidTest.apk","appId":"io.appium.uiautomator2.server.test"}]
[AndroidUiautomator2Driver@e8c7 (beaa697d)] Server packages are not going to be (re)installed
# --列出含有单元测试 case 的应用
[ADB] Running '/Users/lixu/Library/Android/sdk/platform-tools/adb -P 5037 -s emulator-5554 shell pm list instrumentation'
[AndroidUiautomator2Driver@e8c7 (beaa697d)] Instrumentation target 'io.appium.uiautomator2.server.test/androidx.test.runner.AndroidJUnitRunner' is available
# 启动 UIAutomator2 server
[ADB] Running '/Users/lixu/Library/Android/sdk/platform-tools/adb -P 5037 -s emulator-5554 shell am force-stop io.appium.uiautomator2.server.test'
[AndroidUiautomator2Driver@e8c7 (beaa697d)] Starting UIAutomator2 server 5.12.16
[AndroidUiautomator2Driver@e8c7 (beaa697d)] Using UIAutomator2 server from '/Users/lixu/.appium/node_modules/appium-uiautomator2-driver/node_modules/appium-uiautomator2-server/apks/appium-uiautomator2-server-v5.12.16.apk' and test from '/Users/lixu/.appium/node_modules/appium-uiautomator2-driver/node_modules/appium-uiautomator2-server/apks/appium-uiautomator2-server-debug-androidTest.apk'
# 初始化
[AndroidUiautomator2Driver@e8c7 (beaa697d)] The initialization of the instrumentation process took 2038ms
[AndroidUiautomator2Driver@e8c7 (beaa697d)] Matched '/session' to command name 'createSession'
#
[AndroidUiautomator2Driver@e8c7 (beaa697d)] Proxying [POST /session] to [POST http://127.0.0.1:8200/session] with body:
# 使用ADB启动
[ADB] Running '/Users/lixu/Library/Android/sdk/platform-tools/adb -P 5037 -s emulator-5554 shell am start -W -n com.tencent.wework/.launch.LaunchSplashActivity -S -a android.intent.action.MAIN -c android.intent.category.LAUNCHER -f 0x10200000'
{.hidden .audio .subtitle}
通过工具分析过程
除了日志可以看到整个过程之外,还可以通过 WireShark 对中间的通信进行抓包。可以清楚的看到整个流程。
除了日志可以看到整个过程之外,还可以通过 WireShark 对中间的通信进行抓包。可以清楚的看到整个流程。
总结
- 原理分析
- 日志分析
iOS 也是类似的通信过程,只是使用的 driver 和监听的端口不一样。和 iOS 设备通讯是需要使用的是 XCUItest。同理,其实 appium 去操作不同的应用,使用的就是对应的 driver,比如 chromeium-driver、flutter-driver、espresso-driver、windows-driver、mac2-driver 等等。所以其实 appium 设计中非常厉害的一点就在这里。这些 app 自动化测试的相关工具,有的只针对 android 设备,有的只支持 iOS 设备。但是 appium 就可以做到多平台都支持。其实就是因为它的工具都是模块化的设计,从客户端、到服务端、到移动端,它把对应的依赖拆分的特别细,这样就使得它的可拓展性特别强。假设我们现在多了一种平台类型,其实 appium 的客户端和服务端不用做太多的改动,只需要给新平台新开发一个 driver 就可以去驱动它了。这其实就是 appium 强大的一点。客户端其实也是一样,appium 是怎么做到支持多语言的,其实就是因为客户端和服务端已经做了解耦,所以才能做到多种客户端都能调 Server。所以说我们学习一个框架,不仅要了解它是怎么使用的,它的一些好的设计思想,在我们后面有机会去做一些框架开发的时候,一定要去借鉴,一定要去学习的。这就是 appiuim 的原理分析,我们可以通过日志进一步的理解整个的工作过程。这可以帮助我们更好的使用 appium。