干货|app自动化测试之Appium 源码修改定制分析

简介: 干货|app自动化测试之Appium 源码修改定制分析

Appium 是由 Node.js 来实现的 HTTP 服务,它并不是一套全新的框架,而是将现有的优秀的框架进行了集成,在 Selenium WebDriver 协议(JsonWireProtocol/Restful web service)的基础上增加了移动端的支持,使 Appium 满足多方面的需求。

官方提供更详细的 Appium 结构说明:https://appium.io/docs/en/contributing-to-appium/appium-packages/

Appium 框架结构

Appium 是由多个子项目构成的,github 访问如下图:

1080×543 99.2 KB


Appium 由 Appium 以及其它的工作引擎包括:appium-xcuitest-driver、appium-android-driver、appium-ios-driver、appium-uiautomator2-server、appium-base-driver 等组成。下载 Appium 这个项目进行分析,发现 Appium 有着非常复杂的目录结构,如下图:

其中重要的目录如下:

项目中有个文件 package.json ,这个文件是项目的描述文件。对项目或者模块包的描述,比如项目名称,项目版本,项目执行入口文件,项目贡献者等等。npm install命令会根据这个文件下载所有依赖模块,查看这个文件可以看到如下的信息:

"dependencies": {
    "@babel/runtime": "^7.6.0",
    "appium-android-driver": "^4.20.0",
    "appium-base-driver": "^5.0.0",
    "appium-espresso-driver": "^1.0.0",
    "appium-fake-driver": "^0.x",
    "appium-flutter-driver": "^0",
    "appium-ios-driver": "4.x",
    "appium-mac-driver": "1.x",
    "appium-support": "2.x",
    "appium-tizen-driver": "^1.1.1-beta.4",
    "appium-uiautomator2-driver": "^1.37.1",
    "appium-windows-driver": "1.x",
    "appium-xcuitest-driver": "^3.0.0",
    ...
  },

dependencies 表示此模块依赖的模块和版本信息。从这里面可以看到它依赖很多 driver ,比如 appium-android-driver、appium-base-driver、appium-espresso-driver、appium-ios-driver、appium-uiautomator2-driver 等等。下面我们会根据 appium-uiautomator2-driver 重点对 Android 测试驱动的源码进行分析。

appium-uiautomator2-server

appium-uiautomator2-server 是针对 UiAutomator V2 提供的服务,是一个运行在设备上的 Netty 服务器,用来监听指令并执行 UiAutomator V2 命令。

早期版本 Appium 通过 appium-android-bootstrap 实现与 UiAutomator V1 的交互,UiAutomator2 修复了 UiAutomator V1 中遇到的大多数问题,最重要的是实现了与 Android 系统更新的分离。

Appium 底层执行 Android 测试真正的工作引擎是一个 JAVA 项目 appium-uiautomator2-server。可以将这个项目克隆到本地,使用 Android Studio 工具或者其它的 JAVA 项目 IDE 工具打开这个项目。

appium-uiautomator2-server启动

从 README 文件可以看到启动服务的方式:

Starting server
push both src and test apks to the device \
and execute the instrumentation tests.
adb shell am instrument -w \
io.appium.uiautomator2.server.test/\
androidx.test.runner.AndroidJUnitRunner

找到 AppiumUiAutomator2Server.java 这个文件,如下图:

1080×500 170 KB


startServer( ) 方法就是它的启动入口函数。这个函数里面调用了 ServerInstrumentation 类里面的 startServer( ) 方法。如下图:

1080×546 172 KB


startServer( ) 方法会创建一个新的线程来处理一系列的逻辑。

AppiumServlet解析

AppiumServlet 是一个典型 HTTP 请求的处理协议。使用 AppiumServlet 来管理请求,并将 Driver 发过来的请求转发给对应 RequestHandler,它会监听下面的 URL

...
register(postHandler, new FindElement(“/wd/hub/session/:sessionId/element”));
register(postHandler, new FindElements(“/wd/hub/session/:sessionId/elements”));
...

当这些 URL 有请求过来,AppiumServlet 会对它执行相关的处理。比如查找元素、输入、点击等操作。以查找元素为例,实现类里可以看到下面一段代码:

...
final String method = payload.getString("strategy");
final String selector = payload.getString("selector");
final String contextId = payload.getString("context");
...

通过这三个属性“strategy”、“selector”、“context” 来定位元素。在 Appium 对应的日志中可以看到这个操作。

2020-04-08 10:42:37:928 [HTTP] --> POST /wd/hub/session/f99fe38b-445b-45d2-bda0-79bf12e8910e/element
2020-04-08 10:42:37:929 [HTTP] {"using":"xpath",\
"value":"//*[@text=\"交易\"]"}
2020-04-08 10:42:37:930 [W3C (f99fe38b)] Calling \
AppiumDriver.findElement() with args: ["xpath","//*[@text=\"交易\"]","f99fe38b-445b-45d2-bda0-79bf12e8910e"]
...
2020-04-08 10:42:37:931 [WD Proxy] Matched '/element' to \
command name 'findElement'
2020-04-08 10:42:37:932 [WD Proxy] Proxying [POST /element] to \
[POST http://127.0.0.1:8200/wd/hub/session/\
0314d14d-b580-4098-a559-602559cd7277/element] \
with body: {"strategy":"xpath","selector":\
"//*[@text=\"交易\"]","context":"","multiple":false}
...
2020-04-08 10:42:39:518 [W3C (f99fe38b)] Responding \
to client with driver.findElement() \
result: {"element-6066-11e4-a52e-4f735466cecf":\
"c57c34b7-7665-4234-ac08-de11641c8f56",\
"ELEMENT":"c57c34b7-7665-4234-ac08-de11641c8f56"}
2020-04-08 10:42:39:519 [HTTP] <-- POST /wd/hub/session/f99fe38b-445b-45d2-bda0-79bf12e8910e/element 200 1590 ms - 137

上面代码,定位元素的时候会发送一个 POST 请求,Appium 会把请求转为 UiAutomatorV2 的定位,然后转发给 UiAutomatorV2。

扩展功能

在 FindElement.java 中实现了 findElement( ) 方法,如下图:

private Object findElement(By by) throws UiAutomator2Exception, UiObjectNotFoundException {
        refreshAccessibilityCache();
        if (by instanceof ById) {
            String locator = rewriteIdLocator((ById) by);
            return CustomUiDevice.getInstance().findObject(androidx.test.uiautomator.By.res(locator));
        } else if (by instanceof By.ByAccessibilityId) {
            return CustomUiDevice.getInstance().findObject(androidx.test.uiautomator.By.desc(by.getElementLocator()));
        } else if (by instanceof ByClass) {
            return CustomUiDevice.getInstance().findObject(androidx.test.uiautomator.By.clazz(by.getElementLocator()));
        } else if (by instanceof By.ByXPath) {
            final NodeInfoList matchedNodes = getXPathNodeMatch(by.getElementLocator(), null, false);
            if (matchedNodes.isEmpty()) {
                throw new ElementNotFoundException();
            }
            return CustomUiDevice.getInstance().findObject(matchedNodes);
        }
        ...
    }

findElement( ) 方法具体的提供了 ById、ByAccessibilityId、ByClass、ByXpath 等方法,可以扩展这部分功能,如果将来引申出来一些功能,比如想要通过图片、AI 定位元素,可以在上面的 findElement( ) 方法里面添加 else if (by instanceof ByAI) 方法,来创建新类型ByAI并且增加功能的实现。比如未来新增了 AI 来定位元素的功能,可以使用 AI 的插件(基于 nodejs 封装的一个插件)test.ai 插件(https://github.com/testdotai/appium-classifier-plugin)

用法:

driver.find_element('-custom', 'ai:cart');

项目构建与apk安装

完成代码的修改之后需要重新编译生成相应的 apk 文件,并放到 Appium 对应的目录下。

Android Studio → 项目 Gradle → appium-uiautomator2-server-master → Task-other 下。

分别双击 assembleServerDebug 与 assembleServerDebugAndroidTest 即可完成编译,编译完成会在目录下生成对应的两个 apk 文件。

  • assembleServerDebugAndroidTest.apk

构建后 apk 所在目录:app/build/outputs/apk/androidTest/server/debug/appium-uiautomator2-server-debug-androidTest.apk 这个 apk 是个驱动模块,负责创建会话,安装 UiAutomator2-server.apk 到设备上,开启 Netty 服务。

  • assembleServerDebug

构建后 apk 所在目录:app/build/outputs/apk/server/debug/appium-uiautomator2-server-v4.5.5.apk,这是服务器模块,当驱动模块初始化完毕,服务器就会监听 PC 端 Appium 发送过来的请求,将请求发送给真正底层的 UiAutomator2。

另外,也可以使用命令来进行构建:

gradle clean assembleE2ETestDebug assembleE2ETestDebugAndroidTest

将编译完成的 APK,覆盖 Appium 目录下对应的 APK 文件。需要先使用命令查找 Appium 安装目录下的 Uiautomator server 对应的 APK,MacOS 操作命令如下:

find /usr/local/lib/node_modules/appium -name "*uiautomator*.apk"

使用上面的命令会发现关于 Uiautomator 的两个 apk 文件,如下:

$ find /usr/local/lib/node_modules/appium -name \
"*uiautomator*.apk"
/usr/local/lib/node_modules/appium/node_modules\
/appium-uiautomator2-server/apks/\
appium-uiautomator2-server-v4.5.5.apk
/usr/local/lib/node_modules/appium/\
node_modules/appium-uiautomator2-server\
/apks/appium-uiautomator2-server-debug-androidTest.apk

将编译好的 APK 替换这个目录下的 APK 即可。

客户端会传递 Desired Capabilities 给 Appium Server 创建一个会话,Appium Server 会调用 appium-uiautomator2-driver 同时将 UiAutomator2 Server 的两个 apk 安装到测试设备上(也就是上面生成的两个 apk 文件)。

相关文章
|
5天前
|
Java Android开发
Rockchip系列之CAN APP测试应用实现(4)
Rockchip系列之CAN APP测试应用实现(4)
24 1
|
3天前
|
数据采集 Java 开发工具
一文2500字从0到1教你搭建Android自动化python+appium环境
一文2500字从0到1教你搭建Android自动化python+appium环境
一文2500字从0到1教你搭建Android自动化python+appium环境
|
5天前
|
机器学习/深度学习 人工智能 数据管理
深入分析自动化测试中的挑战与机遇
【5月更文挑战第9天】随着软件行业的迅速发展,自动化测试已经成为确保软件质量、提高开发效率的关键手段。然而,在实施自动化测试过程中,企业和测试人员面临着众多挑战,包括测试脚本的维护问题、测试数据管理、与持续集成/持续部署(CI/CD)流程的融合等。本文将探讨这些挑战,并分析在这些挑战背后所隐藏的机遇,比如测试自动化工具的创新使用、人工智能(AI)在测试中的应用以及测试策略的优化。通过案例分析和最新行业趋势的讨论,我们旨在为读者提供对自动化测试未来发展的深刻见解。
|
5天前
|
XML 数据格式
Xpath高阶定位技巧,轻松玩转App测试元素定位!
XPath是一种用于XML文档中节点定位的语言,支持逻辑运算符(and、or、not)、轴定位、谓词和内置函数。
19 0
|
5天前
|
机器学习/深度学习 人工智能 算法
深入分析自动化测试中AI驱动的测试用例生成
【5月更文挑战第4天】随着人工智能(AI)技术的飞速发展,其在软件测试领域的应用也日益广泛。特别是在自动化测试过程中,AI技术能够显著提高测试用例的生成效率和质量。本文将探讨AI在自动化测试用例生成中的应用原理、优势以及面临的挑战,并展示通过AI技术优化测试流程的实际案例。
60 8
|
5天前
|
中间件 测试技术 API
探索自动化测试工具的新边界:Selenium与Appium的集成实践
【4月更文挑战第30天】 随着移动应用和Web应用的不断融合,传统的自动化测试工具需要适应新的测试环境。本文将详细分析Selenium和Appium这两款流行的自动化测试工具的集成实践,探讨如何构建一个能够同时支持Web和移动端应用的自动化测试框架。通过对比两者的技术架构、功能特性以及在实际项目中的集成过程,我们旨在为读者提供一个清晰的指导,帮助他们在复杂的应用环境中实现高效、稳定的自动化测试流程。
|
5天前
|
前端开发 JavaScript 测试技术
深入探索自动化测试框架:Selenium与Appium的对比分析
【4月更文挑战第29天】 在快速迭代的软件发展环境中,自动化测试已成为确保软件质量和加速产品上市的关键步骤。本文将重点探讨两种广泛使用的自动化测试框架——Selenium和Appium,通过对比它们的核心特性、适用场景及执行效率,为软件开发和测试团队提供选择指南。文章不仅分析了各自的技术架构和脚本语言支持,还讨论了它们在处理Web应用和移动应用测试时的优缺点,旨在帮助读者根据项目需求做出更加明智的选择。
|
5天前
|
机器学习/深度学习 人工智能 算法
深入分析自动化测试中AI驱动的测试用例生成技术
【4月更文挑战第29天】随着人工智能技术的不断发展,其在软件测试领域的应用也越来越广泛。本文主要探讨了AI驱动的测试用例生成技术在自动化测试中的应用,以及其对提高测试效率和质量的影响。通过对现有技术的深入分析和实例演示,我们展示了AI如何通过学习和理解软件行为来自动生成有效的测试用例,从而减少人工编写测试用例的工作量,提高测试覆盖率,降低错误检测的成本。
|
5天前
|
XML 数据格式 Python
App测试中,强制等待和隐式等待谁更强?
本文介绍了在自动化脚本中添加等待以确保与应用程序同步的重要性。由于应用响应时间的不确定性,适当等待能防止脚本在操作未完成前继续执行,提高测试稳定性。等待包括强制等待(如`time.sleep()`)、隐式等待(全局设置查找元素的等待时间)和显式等待(根据预期条件等待)。示例代码展示了如何在Python的Appium测试中应用这些等待策略,以优化脚本的可靠性和与应用的同步。
24 0
|
5天前
|
测试技术 Python
App自动化测试中,如何更好地处理弹窗?
在App自动化测试中,处理弹窗异常是保证测试稳定性和可靠性的重要环节。当遇到广告弹窗、升级提示等不定时出现的UI元素时,可以采用黑名单处理方法,如上述Python代码示例,通过尝试点击黑名单中的元素来避免干扰。同时,利用异常处理装饰器可以增强函数功能,保持代码整洁,当异常发生时记录日志、截图并保存页面源代码,便于问题排查。这两种策略能有效提升测试的效率和质量。
9 0

热门文章

最新文章