你真的了解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日志角度了解相关的操作逻辑

复制代码
  @classmethod
   def 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有新的了解,如果有更多想法也欢迎一起探讨!卷起来🤓

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

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

软件测试面试文档

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

视频文档获取方式:

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

相关推荐
niuniu_6661 天前
安全性测试(Security Testing)
测试工具·单元测试·appium·测试·安全性测试
niuniu_6662 天前
appium应用测试场景
功能测试·selenium·测试工具·appium·测试
suimeng63 天前
Appium中元素定位的注意点
appium
suimeng65 天前
Appium中元素定位之一个元素定位API
appium
一禅(OneZen)5 天前
【L2.第二章】Appium 元素定位工具
python·selenium·appium·自动化·web
suimeng66 天前
Appium中元素定位之一组元素定位API
appium
开水好喝7 天前
Appium Inspector使用教程
appium
曦若(xi ruo)16 天前
自动化APP测试APPium的元素等待
运维·appium·自动化
qq_白羊座20 天前
UI自动化:poium测试库使用文档
python·selenium·ui·appium
fantasy_420 天前
Appium高级操作--ActionChains类、Toast元素识别、Hybrid App操作、手机系统API的操作
android·python·appium·自动化