前言
要想深入地掌握任何一门测试工具,对工具本身的架构、原理、使用的协议及相关知识点都必须要有相关的了解和认识,才能做到灵活使用。更重要的是,一旦出了问题,解决问题的时候才会有思路,大概能够知道问题出在什么地方,再去针对性地调试和解决。所以,其实任何工具单纯使用都不是很难,你和高手之间就只隔着九个字——“知其然,且知其所以然”。
好了,言归正传,在本篇我们来先聊聊关于Appium的原理有关的topic。那么我们在讨论Appium的原理时,究竟在说些什么呢?其实离不开以下几点:
△ Appium的架构
△ Appium中非常重要的协议-JSON wire protocol
△ Appium的中的session机制
△ Appium的必要配置(desired capabilities)
△ Appium的Server以及客户端的相关库
接下来我们一个一个地介绍。
一、Appium的架构
Appium的本质是什么呢?熟悉Selenium webdriver的人可以把Appium看作是一个基于移动平台的webdriver。它跟selenium webdriver一样,也是基于HTTP协议、并用Node.js封装的一个移动平台测试框架,只不过它是专门用于移动平台的测试而已。它处理HTTP请求的方式与Selenium Webdriver一样,即由server端接收客户端发送过来的遵循JSON协议的HTTP请求,并按照实际测试的平台来调用平台自身的测试组件来处理这些请求,以达到跨平台测试的效果。
下面我们利用android平台的处理过程来给大家举个栗子。
在android平台使用appium来进行测试时,如果android API是大于或等于17的,则其底层是调用的Uiautomator测试框架,而UIautomator则是android平台自带的UI测试框架,所以稳定性、兼容性啥的都还不错。当API低于17时,由于不支持Uiautomator,则是调用的selendroid测试框架来完成,具体架构及请求处理过程如下图所示:
由图上可以看出来,当我们运行我们所写好的Appium测试脚本时,Appium会将相应的测试命令以JSON的形式发送给Appium server,而Appium server则会根据被测平台android API的版本来调用不同的测试组件(低于17调selendroid,大于或等于17调UIautomator)。在这里,还有一个比较重要的角色,即bootstrap.jar,这个jar包可以理解为放在手机端的一个TCP服务器,它的主要作用是消息的传递和测试组件调度。它以jar包形式存在,并与UIautomator或selendroid进行通信,确保PC端传入的命令可以在手机端正确执行(后面会有专门的部分来分析这个bootstrap的源码,从而搞清楚它的运行机制,在这里大家先了解一下)。
上面是对Appium运行机制的基本介绍,我们再来看看Appium的加载流程:
1.调用android adb完成基本的系统操作和初始化事件
2.在android上部署bootstrap.jar包并启动
3. Forward(分发)android的端口到PC机,方便测试命令的传输
4. PC端监听端口接收请求,并使用JSON wire protocol协议来解析
5.把解析好的命令通过forward的端口发给bootstrap.jar
6.由bootstrap.jar最终在手机端调用Uiautomator或selendroid完成实际的具体测试操作
二、关于JSON wire protocol
JSON wire protocol(又名基于JSON的有线传输协议),它是由webdriver开发者发明的一种传输协议,现在基本已经成为一个标准的W3C标准了。Appium的核心就是一个遵守REST设计风格的web服务器,它接受客户端的连接,接收客户端的命令,在手机设备上执行命令,然后通过HTTP的响应收集命令执行的结果。这种架构给我们提供了很好的开放特性:只要某种语言有http客户端的api,我们就可以通过这个语言写我们的测试代码。最初webdriver以及它所依赖的JSON WP的目标是通过调用Firefox driver、IE driver等调用浏览器的内核相关API,完成web页面的测试。
Appium在传统的JSON WP的基础上,实现了移动端的Mobile JSON WP,它是selenium JSON WP的扩展,也主要面向移动端做了大量的优化,除了常规的app中的元素识别、对象操作外,还包括安装、卸载app等,都可以做到,这是其他常见的移动测试工具所不具备的能力。
下面我们列举一些在Appium中使用的,且基于标准RESTful API的接口例子:
/session/:sessionId
/session/:sessionId/element
/session/:/sessionId/elements
……
当然还有很多其他的接口,Appium提供的客户端库则具备调用这些REST API的能力。比如AppiumDriver.getPageSourece();当你在appium中调用这个方法的时候,appium会发出一个HTTP请求到Appiumserver,调用具有相应方法的API的端点(endpoint),这个API会调用像下面这个RESTful API接口来进行处理:
/session/:sessionId/source
PC端的客户端组件会通过测试脚本向Appium Server发送一个JSON格式的请求,Appium server通过调用上面这个API接口地址来获得页面源码。当被测应用是个基于web网页的应用时,它会将页面的源码以字符串格式进行返回。而如果当被测应用是个原生app时,Appium server将会最终以XML文件格式返回被测应用的UI层级视图。具体的返回响应文本格式根据被测平台和应用也有很大的区别。
三、Appium会话
每一次当Appium server成功启动后,客户端的测试库(client library)会要求与Server创建一个会话(session)。会话的作用是为了确保能区别不同的客户端请求与不同的被测应用,每个特定的会话都有一个特定的sessionId参数。每次测试开始时,客户端将初始化一个session会话,虽然不同的语言初始化的方式不同,但是他们都要发送POST/session请求到服务器端,这些请求里面都会带有一个对象:desired capabilities ,这个时候服务器端会启动自动化session然后返回一个session ID,以后的命令都会用这个seesion ID去匹配。
四、关于desired capabilities
desired capabilities是一个JSON对象,由一系列的键值对组成,里面包含了各种各样的信息。发送到服务器端后,server解析这些信息就知道了客户端对哪种session感兴趣,然后就会启动相应的session。这里面的信息会影响着服务器端启动session的类型。比如你platformName的值为ios,就是告诉服务器启动一个ios的session,而不是android seesion。如果safariAllowPopups的值为true,这是告诉safari类的自动化session,可以使用js打开新窗口。具体信息查看capabilities doc详细了解,后面我们用一篇来介绍常见desired capabilities的作用。
五、Appium的Server以及客户端的相关库
Appium server是PC端与不同的移动端系统(ios,android)进行交互的主要服务器,之前所说的每个客户端在建立测试时所需要的session会话就是由server建立的。它的本质是一个HTTP服务器,由node.js编写而成,并使用了跟selenium server相同的一些理念(如基于REST风格的API设计、JSON WP)。它负责识别来自客户端的HTTP请求并将这些请求发送给不同的平台。我们可以通过下载源码进行编译或直接通过NPM进行安装的方式来运行Appium server,同时也可以安装并运行它的GUI版本。appium server的官方下载网址是http://appium.io。
Appium另一个非常大的优势是由于它的核心库API是基于REST规范开发的,所以无论什么语言,只要其支持发送HTTP请求,都可以用来编写测试代码并与之进行交互,减少了大家学习某种特定语言的成本。目前使用比较广泛的语言包括Java、python、C#、ruby等。并且Appium扩展了传统的基于web的webdriver的客户端测试库,并专门针对移动设备测试提供了特定的测试命令接口,例如移动设备上多点触摸、手势操作等,正是由于其做了这些专门的扩展,所以我们在使用appium来做移动端的自动化测试的时候,需要下载其专用的客户端测试库来代替传统的web driver所使用的测试库。
主要参考资料:由PACKT出版的《Appium Essential》一书,但部分内容根据实际情况本文作者有增删。