
前言
要想深入地掌握任何一門測試工具,對(duì)工具本身的架構(gòu)、原理、使用的協(xié)議及相關(guān)知識(shí)點(diǎn)都必須要有相關(guān)的了解和認(rèn)識(shí),才能做到靈活使用。更重要的是,一旦出了問題,解決問題的時(shí)候才會(huì)有思路,大概能夠知道問題出在什么地方,再去針對(duì)性地調(diào)試和解決。所以,其實(shí)任何工具單純使用都不是很難,你和高手之間就只隔著九個(gè)字——“知其然,且知其所以然”。
好了,言歸正傳,在本篇我們來先聊聊關(guān)于Appium的原理有關(guān)的topic。那么我們在討論Appium的原理時(shí),究竟在說些什么呢?其實(shí)離不開以下幾點(diǎn):
△ Appium的架構(gòu)
△ Appium中非常重要的協(xié)議-JSON wire protocol?
△ Appium的中的session機(jī)制?
△ Appium的必要配置(desired capabilities)
△ Appium的Server以及客戶端的相關(guān)庫
接下來我們一個(gè)一個(gè)地介紹。
一、Appium的架構(gòu)
Appium的本質(zhì)是什么呢?熟悉Selenium?webdriver的人可以把Appium看作是一個(gè)基于移動(dòng)平臺(tái)的webdriver。它跟selenium webdriver一樣,也是基于HTTP協(xié)議、并用Node.js封裝的一個(gè)移動(dòng)平臺(tái)測試框架,只不過它是專門用于移動(dòng)平臺(tái)的測試而已。它處理HTTP請求的方式與Selenium Webdriver一樣,即由server端接收客戶端發(fā)送過來的遵循JSON協(xié)議的HTTP請求,并按照實(shí)際測試的平臺(tái)來調(diào)用平臺(tái)自身的測試組件來處理這些請求,以達(dá)到跨平臺(tái)測試的效果。
下面我們利用android平臺(tái)的處理過程來給大家舉個(gè)栗子。
在android平臺(tái)使用appium來進(jìn)行測試時(shí),如果android API是大于或等于17的,則其底層是調(diào)用的Uiautomator測試框架,而UIautomator則是android平臺(tái)自帶的UI測試框架,所以穩(wěn)定性、兼容性啥的都還不錯(cuò)。當(dāng)API低于17時(shí),由于不支持Uiautomator,則是調(diào)用的selendroid測試框架來完成,具體架構(gòu)及請求處理過程如下圖所示:

由圖上可以看出來,當(dāng)我們運(yùn)行我們所寫好的Appium測試腳本時(shí),Appium會(huì)將相應(yīng)的測試命令以JSON的形式發(fā)送給Appium server,而Appium server則會(huì)根據(jù)被測平臺(tái)android API的版本來調(diào)用不同的測試組件(低于17調(diào)selendroid,大于或等于17調(diào)UIautomator)。在這里,還有一個(gè)比較重要的角色,即bootstrap.jar,這個(gè)jar包可以理解為放在手機(jī)端的一個(gè)TCP服務(wù)器,它的主要作用是消息的傳遞和測試組件調(diào)度。它以jar包形式存在,并與UIautomator或selendroid進(jìn)行通信,確保PC端傳入的命令可以在手機(jī)端正確執(zhí)行(后面會(huì)有專門的部分來分析這個(gè)bootstrap的源碼,從而搞清楚它的運(yùn)行機(jī)制,在這里大家先了解一下)。
上面是對(duì)Appium運(yùn)行機(jī)制的基本介紹,我們再來看看Appium的加載流程:
1.調(diào)用android adb完成基本的系統(tǒng)操作和初始化事件
2.在android上部署bootstrap.jar包并啟動(dòng)
3. Forward(分發(fā))android的端口到PC機(jī),方便測試命令的傳輸
4. PC端監(jiān)聽端口接收請求,并使用JSON wire protocol協(xié)議來解析
5.把解析好的命令通過forward的端口發(fā)給bootstrap.jar
6.由bootstrap.jar最終在手機(jī)端調(diào)用Uiautomator或selendroid完成實(shí)際的具體測試操作
二、關(guān)于JSON wire?protocol
JSON wire protocol(又名基于JSON的有線傳輸協(xié)議),它是由webdriver開發(fā)者發(fā)明的一種傳輸協(xié)議,現(xiàn)在基本已經(jīng)成為一個(gè)標(biāo)準(zhǔn)的W3C標(biāo)準(zhǔn)了。Appium的核心就是一個(gè)遵守REST設(shè)計(jì)風(fēng)格的web服務(wù)器,它接受客戶端的連接,接收客戶端的命令,在手機(jī)設(shè)備上執(zhí)行命令,然后通過HTTP的響應(yīng)收集命令執(zhí)行的結(jié)果。這種架構(gòu)給我們提供了很好的開放特性:只要某種語言有http客戶端的api,我們就可以通過這個(gè)語言寫我們的測試代碼。最初webdriver以及它所依賴的JSON WP的目標(biāo)是通過調(diào)用Firefox driver、IE driver等調(diào)用瀏覽器的內(nèi)核相關(guān)API,完成web頁面的測試。
Appium在傳統(tǒng)的JSON WP的基礎(chǔ)上,實(shí)現(xiàn)了移動(dòng)端的Mobile JSON WP,它是selenium JSON WP的擴(kuò)展,也主要面向移動(dòng)端做了大量的優(yōu)化,除了常規(guī)的app中的元素識(shí)別、對(duì)象操作外,還包括安裝、卸載app等,都可以做到,這是其他常見的移動(dòng)測試工具所不具備的能力。
下面我們列舉一些在Appium中使用的,且基于標(biāo)準(zhǔn)RESTful API的接口例子:
/session/:sessionId
/session/:sessionId/element
/session/:/sessionId/elements
……
當(dāng)然還有很多其他的接口,Appium提供的客戶端庫則具備調(diào)用這些REST API的能力。比如AppiumDriver.getPageSourece();當(dāng)你在appium中調(diào)用這個(gè)方法的時(shí)候,appium會(huì)發(fā)出一個(gè)HTTP請求到Appiumserver,調(diào)用具有相應(yīng)方法的API的端點(diǎn)(endpoint),這個(gè)API會(huì)調(diào)用像下面這個(gè)RESTful API接口來進(jìn)行處理:
/session/:sessionId/source
PC端的客戶端組件會(huì)通過測試腳本向Appium?Server發(fā)送一個(gè)JSON格式的請求,Appium server通過調(diào)用上面這個(gè)API接口地址來獲得頁面源碼。當(dāng)被測應(yīng)用是個(gè)基于web網(wǎng)頁的應(yīng)用時(shí),它會(huì)將頁面的源碼以字符串格式進(jìn)行返回。而如果當(dāng)被測應(yīng)用是個(gè)原生app時(shí),Appium server將會(huì)最終以XML文件格式返回被測應(yīng)用的UI層級(jí)視圖。具體的返回響應(yīng)文本格式根據(jù)被測平臺(tái)和應(yīng)用也有很大的區(qū)別。
三、Appium會(huì)話
每一次當(dāng)Appium server成功啟動(dòng)后,客戶端的測試庫(client library)會(huì)要求與Server創(chuàng)建一個(gè)會(huì)話(session)。會(huì)話的作用是為了確保能區(qū)別不同的客戶端請求與不同的被測應(yīng)用,每個(gè)特定的會(huì)話都有一個(gè)特定的sessionId參數(shù)。每次測試開始時(shí),客戶端將初始化一個(gè)session會(huì)話,雖然不同的語言初始化的方式不同,但是他們都要發(fā)送POST/session請求到服務(wù)器端,這些請求里面都會(huì)帶有一個(gè)對(duì)象:desired capabilities ,這個(gè)時(shí)候服務(wù)器端會(huì)啟動(dòng)自動(dòng)化session然后返回一個(gè)session ID,以后的命令都會(huì)用這個(gè)seesion ID去匹配。
四、關(guān)于desired capabilities
desired capabilities是一個(gè)JSON對(duì)象,由一系列的鍵值對(duì)組成,里面包含了各種各樣的信息。發(fā)送到服務(wù)器端后,server解析這些信息就知道了客戶端對(duì)哪種session感興趣,然后就會(huì)啟動(dòng)相應(yīng)的session。這里面的信息會(huì)影響著服務(wù)器端啟動(dòng)session的類型。比如你platformName的值為ios,就是告訴服務(wù)器啟動(dòng)一個(gè)ios的session,而不是android seesion。如果safariAllowPopups的值為true,這是告訴safari類的自動(dòng)化session,可以使用js打開新窗口。具體信息查看capabilities doc詳細(xì)了解,后面我們用一篇來介紹常見desired capabilities的作用。
五、Appium的Server以及客戶端的相關(guān)庫
Appium server是PC端與不同的移動(dòng)端系統(tǒng)(ios,android)進(jìn)行交互的主要服務(wù)器,之前所說的每個(gè)客戶端在建立測試時(shí)所需要的session會(huì)話就是由server建立的。它的本質(zhì)是一個(gè)HTTP服務(wù)器,由node.js編寫而成,并使用了跟selenium server相同的一些理念(如基于REST風(fēng)格的API設(shè)計(jì)、JSON WP)。它負(fù)責(zé)識(shí)別來自客戶端的HTTP請求并將這些請求發(fā)送給不同的平臺(tái)。我們可以通過下載源碼進(jìn)行編譯或直接通過NPM進(jìn)行安裝的方式來運(yùn)行Appium server,同時(shí)也可以安裝并運(yùn)行它的GUI版本。appium server的官方下載網(wǎng)址是http://appium.io。
Appium另一個(gè)非常大的優(yōu)勢是由于它的核心庫API是基于REST規(guī)范開發(fā)的,所以無論什么語言,只要其支持發(fā)送HTTP請求,都可以用來編寫測試代碼并與之進(jìn)行交互,減少了大家學(xué)習(xí)某種特定語言的成本。目前使用比較廣泛的語言包括Java、python、C#、ruby等。并且Appium擴(kuò)展了傳統(tǒng)的基于web的webdriver的客戶端測試庫,并專門針對(duì)移動(dòng)設(shè)備測試提供了特定的測試命令接口,例如移動(dòng)設(shè)備上多點(diǎn)觸摸、手勢操作等,正是由于其做了這些專門的擴(kuò)展,所以我們在使用appium來做移動(dòng)端的自動(dòng)化測試的時(shí)候,需要下載其專用的客戶端測試庫來代替?zhèn)鹘y(tǒng)的web driver所使用的測試庫。
主要參考資料:由PACKT出版的《Appium Essential》一書,但部分內(nèi)容根據(jù)實(shí)際情況本文作者有增刪。