綜述
本文主要介紹了多端自動(dòng)化的實(shí)踐經(jīng)歷而非作為airtest的科普文章(因?yàn)閍irtest的官方文檔真的是已經(jīng)特別全了,非常建議實(shí)踐之前先看一遍文檔,大部分問(wèn)題都能達(dá)到答案),主要敘述了在面對(duì)多端大規(guī)模場(chǎng)景時(shí),自動(dòng)化的技術(shù)選型、方案設(shè)計(jì)、實(shí)踐難點(diǎn)等等。
項(xiàng)目背景介紹
所在項(xiàng)目是一個(gè)多端互動(dòng)的場(chǎng)景,是一對(duì)多的業(yè)務(wù)實(shí)現(xiàn),具體是由一臺(tái)winpad的教師端,對(duì)多臺(tái)安卓的學(xué)生端,在同一局域網(wǎng)內(nèi),進(jìn)行指令的發(fā)送和接收,從而產(chǎn)生互動(dòng),指令的中轉(zhuǎn)由臺(tái)服務(wù)(服務(wù)器+AP)實(shí)現(xiàn)。
需求產(chǎn)生的背景介紹
原始的客戶訴求,是因?yàn)闃I(yè)務(wù)測(cè)試在執(zhí)行這樣一對(duì)多的測(cè)試(以下簡(jiǎn)稱為大規(guī)模互動(dòng))中,因?yàn)樾枰鎸?shí)模擬場(chǎng)景,所以往往需要在一臺(tái)教師端和60臺(tái)學(xué)生端之間來(lái)回操作,極為消耗人力資源(平均一次大約需要2人1天的工時(shí)),因此希望得到一種技術(shù)手段,節(jié)約在大規(guī)?;?dòng)測(cè)試中的開(kāi)銷。
技術(shù)選型
基于原始的客戶訴求,我們將具體實(shí)現(xiàn)定義為了ui自動(dòng)化類型,以下是技術(shù)選型的分析過(guò)程。
技術(shù)要求
-
統(tǒng)一性
大規(guī)模互動(dòng)產(chǎn)生在不同的系統(tǒng)間,教師端的系統(tǒng)是win10,而學(xué)生端的系統(tǒng)是android,因此,我們希望最好可以由同一套框架實(shí)現(xiàn)對(duì)兩端的驅(qū)動(dòng),這樣整體便于設(shè)計(jì)和驅(qū)動(dòng)。
-
高兼容性
由于教師端的實(shí)現(xiàn)并不是標(biāo)準(zhǔn)的windows應(yīng)用實(shí)現(xiàn)方法,而是通過(guò)c+nodejs再由electron做封裝,因此,很多元素用傳統(tǒng)的windows的查找框架uiautomation不易找到,而由于客戶端對(duì)webview的實(shí)現(xiàn)寫死了啟動(dòng)參數(shù),因此也無(wú)法通過(guò)傳統(tǒng)的cdp進(jìn)行定位,因此,我們希望可以有一個(gè)相對(duì)兼容的解決辦法去定位元素。
-
低侵入性
在學(xué)生端,有著rom級(jí)的mdm安全管控,對(duì)安裝應(yīng)用、網(wǎng)絡(luò)進(jìn)出、adb連接等待都有著嚴(yán)格的規(guī)則,且mdm是和供應(yīng)商聯(lián)合制定的,如果要對(duì)某些地方放行,會(huì)面臨較大的實(shí)現(xiàn)成本問(wèn)題,因此,我們希望整體的實(shí)現(xiàn)方案具有較低的侵入性。
方案對(duì)比
經(jīng)過(guò)調(diào)研,具備以上要求的方案大概有以下:
-
airtest
網(wǎng)易出品的主打圖像識(shí)別的開(kāi)源自動(dòng)化測(cè)試框架,具備三端(web、移動(dòng)、win)驅(qū)動(dòng)能力;且相關(guān)ide、文檔、使用經(jīng)歷較為齊全。
-
騰訊QTA
騰訊出品的開(kāi)源自動(dòng)化測(cè)試框架,具備三端驅(qū)動(dòng)能力,但截至調(diào)研期間,其win端的驅(qū)動(dòng)包還未放出。
-
學(xué)生端appium+教師端pywinauto
appium是老牌的移動(dòng)端測(cè)試框架,pywinauto是win端的gui測(cè)試框架,他們皆可由py進(jìn)行封裝驅(qū)動(dòng)。 但appium存在需要在移動(dòng)端安裝其服務(wù)apk以及通信的需求,會(huì)受到mdm管控。
-
學(xué)生端AccessibilityService+以上教師端方案
通過(guò)AccessibilityService可以實(shí)現(xiàn)學(xué)生端的元素控制,使得學(xué)生端可以無(wú)需連接控制設(shè)備,直接在本機(jī)即可運(yùn)行,但后續(xù)擴(kuò)展能力較低,且難以與教師端實(shí)現(xiàn)相互通信。
綜合以上選擇,認(rèn)為 airtest 現(xiàn)階段較為合適,并且由于是局域網(wǎng)內(nèi)的大規(guī)模通信場(chǎng)景,對(duì)無(wú)線帶寬本身就有壓力,因此,對(duì)學(xué)生端的驅(qū)動(dòng)方式采用有線adb而非無(wú)線的方式。
方案設(shè)計(jì)
整體架構(gòu)
原本更為合適的架構(gòu)形態(tài)可能是通過(guò)rpc的方式完成端對(duì)端通信(具體參見(jiàn)文檔:基于rpc的多端互動(dòng)自動(dòng)化方案),由于時(shí)間和人力所限,最后簡(jiǎn)化為端對(duì)端之間互不通信,學(xué)生端通過(guò)元素輪詢完成教師端行為的響應(yīng),具體架構(gòu)如下:
1.環(huán)境需求:
硬件
- 學(xué)生端執(zhí)行服務(wù)器 *2臺(tái);
- 教師端執(zhí)行服務(wù)器 *1臺(tái)(如果也在學(xué)生端執(zhí)行服務(wù)器上那么可以沒(méi)有);
- UsbHub *2臺(tái);
- 學(xué)生pad *60臺(tái);
軟件
- 學(xué)生端腳本;
- 教師端腳本
網(wǎng)絡(luò)
- 局域網(wǎng)環(huán)境(超腦環(huán)境)
2.執(zhí)行過(guò)程:
usbhub分別連接上各30臺(tái)學(xué)生端機(jī)器以及執(zhí)行學(xué)生端腳本的服務(wù)器;
-->
在學(xué)生端執(zhí)行服務(wù)器上啟動(dòng)學(xué)生端腳本,此時(shí)學(xué)生端進(jìn)入元素輪詢狀態(tài);
-->
在教師端執(zhí)行服務(wù)器上啟動(dòng)教師端腳本,通過(guò)教師端本身的反饋判斷學(xué)生端是否做完對(duì)應(yīng)動(dòng)作
-->
收集測(cè)試結(jié)果
腳本設(shè)計(jì)
腳本架構(gòu)
腳本的基本設(shè)計(jì)采用元素映射關(guān)系、配置文件、執(zhí)行步驟互相分離的方式,各端的腳本放置在xxx.air的文件夾里,通過(guò)airtest本身的啟動(dòng)cli執(zhí)行。
腳本的目錄結(jié)構(gòu)大致如下:
|-- configs(存放項(xiàng)目運(yùn)行設(shè)置的配置文件目錄)
|'-- run.config
|-- logs(記錄運(yùn)行時(shí)log文件的目錄)
|-- templates(存放報(bào)告模板目錄)
|'-- report_tpl.html
|-- test_XXX.air(某個(gè)端的執(zhí)行腳本)
|'-- action.config(某個(gè)端的運(yùn)行配置)
|'-- element.config(某個(gè)端的元素映射文件)
|'-- test_xxx.py(某個(gè)端的執(zhí)行動(dòng)作腳本庫(kù))
|'-- utils.py(工具集方法)
|-- valid_pic(存放斷言用圖片的目錄)
|-- run.py(總運(yùn)行入口)
腳本實(shí)現(xiàn)能力
腳本主要實(shí)現(xiàn)了以下能力:
-
覆蓋了學(xué)生端、教師端的互動(dòng)主要場(chǎng)景的動(dòng)作執(zhí)行;
-
覆蓋了互動(dòng)主要場(chǎng)景的耗時(shí)統(tǒng)計(jì);
-
教師端、學(xué)生端分別由配置文件定制主要場(chǎng)景的執(zhí)行細(xì)節(jié)(例如執(zhí)行次數(shù),動(dòng)作參數(shù)等等)
-
集成了非主要場(chǎng)景但是常用的工具集(例如adb連接檢測(cè),自動(dòng)安裝卸載apk等等)
-
。。。
關(guān)鍵技術(shù)點(diǎn)實(shí)現(xiàn)
-
多進(jìn)程驅(qū)動(dòng)學(xué)生端執(zhí)行用例
由于互動(dòng)場(chǎng)景基于1對(duì)多,在學(xué)生端這邊需要多臺(tái)設(shè)備進(jìn)行場(chǎng)景互動(dòng),因此,需要同時(shí)驅(qū)動(dòng)多臺(tái)設(shè)備,在實(shí)現(xiàn)上,我們查閱了官方資料,采用了其建議的方式,通過(guò)起多個(gè)進(jìn)程,每個(gè)進(jìn)程分別帶參執(zhí)行airtest的cli命令,從而達(dá)到多設(shè)備驅(qū)動(dòng)的目的。
-
圖像識(shí)別下的斷言
如前文,在精簡(jiǎn)的框架設(shè)計(jì)下,多端互動(dòng)是通過(guò)學(xué)生端輪詢?cè)貋?lái)執(zhí)行互動(dòng)流程的,但是仍然需要對(duì)互動(dòng)結(jié)果的正確性進(jìn)行校驗(yàn)。這里由于框架的限制,我們只采取了單端校驗(yàn),即只對(duì)教師端的互動(dòng)數(shù)據(jù)進(jìn)行校驗(yàn),比如如果有30個(gè)學(xué)生作答成功,那么我們就對(duì)教師端的結(jié)果頁(yè)面進(jìn)行校驗(yàn),看答題人數(shù)是否是30。
具體到校驗(yàn)手段,由于windows端較難獲取元素屬性,所以我們采用了對(duì)關(guān)鍵點(diǎn)進(jìn)行ocr識(shí)別的方式,具體請(qǐng)見(jiàn)文檔 在airtest中使用ocr反向識(shí)別進(jìn)行斷言。
-
執(zhí)行過(guò)程內(nèi)性能數(shù)據(jù)的收集
數(shù)據(jù)收集是指在執(zhí)行過(guò)后,需要給出場(chǎng)景的耗時(shí),例如指令的接受耗時(shí)、頁(yè)面的加載耗時(shí)等等,這塊主要是通過(guò)在學(xué)生端設(shè)備上記錄一個(gè)時(shí)間,作為開(kāi)始時(shí)間,然后測(cè)試結(jié)束后,提取該設(shè)備上的日志分析,最后得出耗時(shí)數(shù)據(jù)。
-
易混淆元素的記錄
由于采用的是圖像識(shí)別的模式,難免遇到元素圖像相似的情況,針對(duì)這種情況,采用的方法是擴(kuò)大可識(shí)別范圍截取元素,并使用target_pos參數(shù)更改選取區(qū)域。
應(yīng)用過(guò)程問(wèn)題與解決
本部分以問(wèn)答的形式展現(xiàn)在airtest應(yīng)用過(guò)程里存在的一些問(wèn)題和解決辦法。
-
為什么執(zhí)行windows端腳本的時(shí)候,鼠標(biāo)可以移動(dòng)到元素上但是執(zhí)行動(dòng)作失???
在win端,airtest的底層是pywinauto,并且基本沒(méi)有任何二次開(kāi)發(fā);遇到這個(gè)問(wèn)題,如果排除掉本身腳本的邏輯、語(yǔ)法問(wèn)題,那么可以試試以管理員身份運(yùn)行腳本。
-
我必須要用官方的ide嘛?
airtest雖然附帶了一個(gè)官方的ide,但是非常不建議把它用作項(xiàng)目的ide,作為項(xiàng)目級(jí)的ide還是比較欠缺工程目錄管理能力和基本的代碼檢查能力等;
建議的方法是,ide僅用作抓取元素時(shí)的錄制工具,但是項(xiàng)目級(jí)別的管理最好還是使用知名的ide。
-
為什么有些windows的窗口用title連接不上?
如果不是你的語(yǔ)法有問(wèn)題,并且你“看起來(lái)”title寫的也對(duì),那么可以在識(shí)別的時(shí)候在pywinauto的底層代碼里,打個(gè)斷點(diǎn),把所有窗口名稱用bytes類型打印出來(lái)看一下;
pywinauto的連接過(guò)程里,是先遍歷所有窗口,然后按你的連接類型做匹配,這里打個(gè)斷點(diǎn),可以看一下你寫的title是不是真的對(duì),因?yàn)樵趯?shí)際的項(xiàng)目里,我們遇到了看起來(lái)是對(duì)的title名稱,但是無(wú)論如何匹配不上,導(dǎo)致無(wú)法連接,最后用bytes模式打印出來(lái)看,發(fā)現(xiàn)是因?yàn)檫@個(gè)窗口的title前面有三個(gè)不可見(jiàn)字符(直接print你是看不見(jiàn)的)。
-
如何提高元素的查找速度?
和傳統(tǒng)的通過(guò)元素屬性查找的方式不同,airtest是基于圖像識(shí)別的,因此,在提高元素查找效率方面,方法也和傳統(tǒng)的有些不同;一個(gè)基本的原則是,被查找的元素的截圖,在整個(gè)畫面里越獨(dú)一無(wú)二,越具備特征性(圖形的特征性而不是顏色),那么就越容易被找到;此外,在對(duì)元素的映射關(guān)系記錄里,增加record_pos和resolution的值,會(huì)極大的增加查找速度和效率。
-
怎么對(duì)沒(méi)找到元素的情況進(jìn)行調(diào)試?
和傳統(tǒng)的通過(guò)元素屬性的查找方式不同,基于圖像識(shí)別的查找方式不存在找不到元素,對(duì)圖像識(shí)別而言,它總是能找到元素的,區(qū)別只是查找到元素的匹配度(threshold)而已,airtest默認(rèn)的threshold是0.7,也就是說(shuō),在他認(rèn)為元素的匹配度為70%以上時(shí),就認(rèn)為找到了這個(gè)元素,才會(huì)對(duì)這個(gè)元素進(jìn)行操作。
不幸的是,往往達(dá)到0.7,也不一定就是真的找到了(但達(dá)不到一般是真沒(méi)找到),如果達(dá)不到匹配度,或者達(dá)到了但也不對(duì),可以在airtest的框架里打斷點(diǎn)。
airrtest的查找機(jī)制是先把當(dāng)前待查找的界面進(jìn)行截圖,我們稱為圖1;然后再根據(jù)你的record_pos,在圖1里算出待識(shí)別區(qū)域,然后把這個(gè)區(qū)域摳出來(lái)保存,我們稱為圖2;最后,再把你的預(yù)先截圖的元素,在圖2里進(jìn)行查找,算出匹配度,如果匹配度在要求之上,那么就記錄這個(gè)位置的坐標(biāo)用于操作。
因此,我們可以分別對(duì)圖1,圖2設(shè)定指定的保存目錄,執(zhí)行一遍后看一下,到底是對(duì)比對(duì)象出了問(wèn)題,還是真的我們?cè)亟貓D特征還不夠。