今天想先給大家分享 1 個(gè)小白用戶的 Airtest 從入門到放棄的故事小 A 是一個(gè)自動(dòng)化的小白,在逛測(cè)試論壇的時(shí)候,偶然間發(fā)現(xiàn)了 Airtest 這個(gè)基于圖像識(shí)別的 UI 自動(dòng)化框架出于好奇,小 A 試用了這個(gè)框架,發(fā)現(xiàn)只需要幾條簡(jiǎn)單的截圖腳本,就可以對(duì)設(shè)備進(jìn)行各種自動(dòng)化操作,于是小 A 成功種草了這個(gè)框架但幾天之后,隨著小 A 的深入使用,他發(fā)現(xiàn)截圖腳本并不是他想象中那么“完美”;有時(shí)候程序會(huì)告訴他?找不到對(duì)應(yīng)的截圖?,有時(shí)候程序又會(huì)?識(shí)別到一些錯(cuò)誤的位置?,又或者他辛苦寫好的截圖腳本,換了一臺(tái)手機(jī)之后,又都識(shí)別不到了......在經(jīng)歷了第 N 次失敗之后,小 A 最終還是放棄了這個(gè)框架看到這里,或許一部分同學(xué)會(huì)覺得感同身受,因?yàn)樽约簞傞_始用 Airtest 這個(gè)框架的時(shí)候,也是經(jīng)常踩到上面所說的坑!Airtest 作為 1 個(gè)自研的測(cè)試框架,它確實(shí)不能做到 “完美” 識(shí)別;但是除了期待以后我們的開發(fā)小姐姐小哥哥們研究出更精確的圖像識(shí)別方案之外,我們還有很多技巧可以提高我們截圖腳本的兼容性下文我們將先了解一下?Airtest 圖像識(shí)別原理相關(guān)的知識(shí)?,然后在實(shí)際案例中,帶大家一起看看11個(gè)截圖技巧 ,幫助大家提升截圖腳本的兼容性。Airtest截圖,你必須知道的幾個(gè)知識(shí)點(diǎn)默認(rèn) Airtest 會(huì)嘗試用?SURFMatching?、TemplateMatching?和?BRISKMatching?這三種算法來進(jìn)行圖像識(shí)別TemplateMatching?屬于?模板匹配算法SURFMatching?和?BRISKMatching?則屬于?特征點(diǎn)匹配方法簡(jiǎn)單點(diǎn)說,模板匹配算法依賴?特征向量?來進(jìn)行圖像匹配,而特征點(diǎn)匹配算法則是依賴于?圖像的特征點(diǎn)?這些算法對(duì)于設(shè)備畫面上唯一的圖標(biāo)、圖像,識(shí)別效果會(huì)比較好,因?yàn)樗鼈儞碛斜容^多的特征向量/特征點(diǎn),而對(duì)于像純文字截圖、含有大量空白背景的截圖,識(shí)別效果則會(huì)差一些我們都知道,純文字截圖中僅僅包含了一些簡(jiǎn)單的筆劃,特征向量/特征點(diǎn)會(huì)比較少,相對(duì)于圖像來說,更容易識(shí)別到錯(cuò)誤的結(jié)果;而空白背景的截圖,各個(gè)像素點(diǎn)的灰度值基本沒有什么變化,所以特征點(diǎn)幾乎沒有,就更容易找不到匹配結(jié)果/匹配到天差地別的結(jié)果出來程序如何根據(jù)算法結(jié)果判定是否找到匹配的截圖
那當(dāng)我們編寫好截圖腳本,并開始運(yùn)行的時(shí)候,程序是如何用這些圖像識(shí)別算法來幫助我們判定是否識(shí)別到結(jié)果的呢?這里先介紹兩個(gè)很重要的名詞:闕值?和?可信度?,他們的取值范圍都是 [0,1];在每一條圖像識(shí)別的腳本中,都會(huì)有1個(gè)用于結(jié)果篩選的闕值,默認(rèn)值為:0.7當(dāng)上述三種算法在執(zhí)行過程中識(shí)別到初始結(jié)果時(shí),就會(huì)計(jì)算出來這個(gè)初始結(jié)果的可信度,當(dāng)?可信度>闕值?的時(shí)候,程序會(huì)認(rèn)為?找到了最佳的匹配結(jié)果?;而當(dāng)?可信度<闕值?的時(shí)候,程序則會(huì)認(rèn)為?沒有找到最佳的匹配結(jié)果?。我們可以在執(zhí)行截圖腳本的時(shí)候,查看 log 窗口,觀察算法識(shí)別結(jié)果的可信度:② 可信度<闕值,程序判定未找到匹配結(jié)果,循環(huán)用三種算法繼續(xù)查找直到超時(shí)了解完截圖相關(guān)的基礎(chǔ)知識(shí)之后,終于到了我們截圖技巧這部分的內(nèi)容,不過需要注意的是,不同場(chǎng)景所應(yīng)用的技巧的大不相同,希望同學(xué)們可以靈活使用:截取圖標(biāo)時(shí)盡量不要截入過多的背景內(nèi)容
舉個(gè)簡(jiǎn)單的例子,比如我們想通過點(diǎn)擊網(wǎng)易云音樂的應(yīng)用圖標(biāo)來打開網(wǎng)易云音樂的app,為了能在不同設(shè)備上都有更好的識(shí)別結(jié)果,我們應(yīng)該盡可能選取下圖中第一種截圖,而不是混入了過多背景的第二種截圖:為了讓大家直觀地看到差別,我們?cè)谠O(shè)備1上截好了上述倆張圖,然后分別在設(shè)備 2 中執(zhí)行,結(jié)果如下:可以看到,沒有截入過多背景的截圖,識(shí)別出來的可信度高達(dá) 0.95;而截入了背景的圖標(biāo)截圖,可信度下降到了 0.88。所以在截取這些特定圖標(biāo)的時(shí)候,盡量減少截入背景,可以有效提高這類截圖腳本的兼容性。打開應(yīng)用盡量使用 start_app 而不是截圖腳本
start_app()?支持 Android 和 iOS 設(shè)備,相對(duì)用截圖腳本來啟動(dòng)應(yīng)用,腳本會(huì)更加簡(jiǎn)潔,兼容性也會(huì)更好:# 打開網(wǎng)易云音樂
start_app("com.netease.cloudmusic")
用 image editor 查看截圖識(shí)別結(jié)果的可信度
我們錄制/編寫好 1 條截圖腳本之后,無需運(yùn)行,可以直接雙擊截圖,進(jìn)入圖片編輯器,點(diǎn)擊左上角的?snapshot+recognition?按鈕,即可查看截圖在當(dāng)前頁(yè)面的識(shí)別情況,包含識(shí)別出來的位置以及識(shí)別結(jié)果的可信度:這個(gè)識(shí)別情況可以作為一個(gè)參考,幫助同學(xué)們快速調(diào)試自己的截圖腳本。巧用 target_pos 點(diǎn)擊截圖的不同位置
默認(rèn)情況下,我們的截圖腳本都是點(diǎn)擊截圖的中心位置,即?target_pos=5?。對(duì)于一張截圖來說,總共有 9 個(gè)?target_pos?,當(dāng)我們把截圖的?target_pos?設(shè)置成不同的值時(shí),腳本會(huì)點(diǎn)擊在截圖不同的位置上:雙擊 IDE 中的截圖即可打開圖片編輯器,右側(cè)可以修改?target_pos?的值:修改完成之后,把截圖腳本切換成代碼模式,我們就可以看到此時(shí)的截圖腳本里面多了?target_pos?這個(gè)參數(shù):touch(Template(r"tpl1598948415043.png", target_pos=6, record_pos=(-0.434, -0.773), resolution=(900, 1600)))
我們?cè)谧鲎詣?dòng)化的時(shí)候,經(jīng)常會(huì)遇到某個(gè)圖標(biāo)堆疊的情況,比如在網(wǎng)易云音樂的某個(gè)歌曲列表中,右側(cè)便羅列了三個(gè)完全一樣的播放按鈕:如果我們的需求是點(diǎn)擊中間那個(gè)按鈕的,僅僅依靠截 1 個(gè)播放按鈕來做識(shí)別,是很難保證具體識(shí)別到三個(gè)按鈕中的具體哪個(gè)按鈕的。此時(shí)我們可以有 2 種截圖方式來實(shí)現(xiàn),一種是在豎著的方向上,擴(kuò)大截圖范圍,讓中間那個(gè)按鈕處于?target_pos=5?的位置上:另一種是在橫著的方向上,擴(kuò)大截圖范圍把左側(cè)的歌曲介紹也一起截圖了,讓中間那個(gè)按鈕處于?target_pos=6?的位置上:這 2 種方式都可以確保我們點(diǎn)到的是中間那個(gè)按鈕(假設(shè)列表歌曲不變的情況下)。所以,當(dāng)精準(zhǔn)截圖(僅截取某個(gè)按鈕/圖標(biāo))不能滿足唯一定位時(shí),我們可以考慮加大截圖范圍,增加更多的特征點(diǎn),確保截圖定位的準(zhǔn)確性。巧用坐標(biāo)進(jìn)行點(diǎn)擊/滑動(dòng)
有時(shí)候,我們?cè)诖蜷_一個(gè) app 時(shí),會(huì)遇到一些過場(chǎng)動(dòng)畫或者是幾張應(yīng)用的介紹頁(yè)。這些過場(chǎng)動(dòng)畫和介紹頁(yè)可能會(huì)隨著版本更新而變化,那么利用截圖點(diǎn)擊,可能需要花費(fèi)我們比較大的精力去維護(hù)這些截圖腳本。其實(shí)這時(shí)候我們完全可以用坐標(biāo)點(diǎn)擊來替代截圖點(diǎn)擊,因?yàn)檫@些過場(chǎng)動(dòng)畫或者介紹頁(yè),只要有任意的點(diǎn)擊動(dòng)作,都可以跳過。在比如說網(wǎng)易云音樂首頁(yè)的輪播圖,可能每天登錄上去都是不一樣的,如果我們用截圖腳本來滑動(dòng)/點(diǎn)擊,那天天都需要維護(hù)這些腳本,還不如替換成坐標(biāo)滑動(dòng)/點(diǎn)擊,更加省心省力:巧用 keyevent("BACK") 替代返回的截圖腳本
很多時(shí)候,我們需要從 APP 的某個(gè)頁(yè)面,回到 APP 首頁(yè),一些同學(xué)可能會(huì)使用一堆的返回圖標(biāo)的截圖語(yǔ)句,來實(shí)現(xiàn)這個(gè)需求:123期896971
實(shí)際上,如果同學(xué)們測(cè)的是安卓設(shè)備,完全可以用?keyevent("BACK")?來替代這個(gè)返回的截圖語(yǔ)句,更加穩(wěn)定高效:IDE 自帶的錄制功能,可以幫助我們的新手同學(xué)快速上手 Airtest 這個(gè)基于圖像識(shí)別的測(cè)試框架,但是自動(dòng)錄制出來的截圖語(yǔ)句,并不是都會(huì)很符合我們的實(shí)際需求,所以我們不能過度依賴錄制功能。我們可以在錄制完畢之后,檢查下有哪些截圖并不是截的很好的,自己再手動(dòng)截取一下,提升整個(gè)腳本的兼容性。畫面切換的時(shí)候,可以多使用 wait 或者 sleep,再進(jìn)行點(diǎn)擊操作
很多新手同學(xué)都很容易犯 1 個(gè)錯(cuò)誤,就是一不小心就寫了很多連續(xù)點(diǎn)擊操作其實(shí),在每一個(gè)點(diǎn)擊操作之后,應(yīng)用畫面也是在實(shí)時(shí)變化的。如果畫面正在加載的時(shí)候,下一個(gè)點(diǎn)擊操作就被執(zhí)行了,就會(huì)很容易導(dǎo)致識(shí)別到錯(cuò)誤位置或者識(shí)別超時(shí)。舉個(gè)例子,進(jìn)入網(wǎng)易云音樂的 app 時(shí),我們同意了服務(wù)條款之后,會(huì)有 1 個(gè)很長(zhǎng)的啟動(dòng)動(dòng)畫,我們只有等待啟動(dòng)動(dòng)畫結(jié)束之后,才能夠進(jìn)行下一步的點(diǎn)擊 “立即體驗(yàn)” 的操作,否則這個(gè)點(diǎn)擊操作很可能因?yàn)樵诘却龁?dòng)動(dòng)畫的過程中而識(shí)別超時(shí):另外,為保證連續(xù)點(diǎn)擊都能夠正常被執(zhí)行,我們還可以在連續(xù)點(diǎn)擊之間用?sleep(1.0)?來緩沖下,減少畫面切換對(duì)連續(xù)點(diǎn)擊操作的影響。上文我們就提到過闕值,它起到結(jié)果篩選的作用。也就是說,如果我們?cè)O(shè)置的闕值過低,就更容易讓錯(cuò)誤的結(jié)果通過;而闕值設(shè)置得過高,就有可能把可信度達(dá)不到要求的正確結(jié)果也過濾掉,導(dǎo)致很難得出有效的識(shí)別結(jié)果。所以我們可以通過合理調(diào)整闕值大小,更好地過濾出我們想要的識(shí)別結(jié)果。舉個(gè)例子,某個(gè)截圖默認(rèn)闕值為:0.7,但是我們多次運(yùn)行之后發(fā)現(xiàn),有一定概率會(huì)識(shí)別到錯(cuò)誤結(jié)果。這時(shí)候我們不妨將闕值調(diào)高一點(diǎn)試試,看看能不能提高正確識(shí)別的概率,如果可以,說明我們的闕值調(diào)整是有效的。在 IDE 中,我們可以雙擊截圖打開圖片編輯器,在右側(cè)修改截圖的闕值:設(shè)置好并關(guān)掉圖片編輯器后,我們?cè)谀_本編寫窗口右鍵切換成代碼模式,可以看到剛才那條截圖腳本多了個(gè)?threshold=0.8?參數(shù):touch(Template(r"tpl1598952570968.png", threshold=0.8, record_pos=(-0.021, 0.121), resolution=(900.0, 1600.0)))
當(dāng)然,我們也可以設(shè)置全局的?threshold?:from airtest.core.setting import Settings as ST
ST.THRESHOLD = 0.7 # 其他語(yǔ)句的默認(rèn)閾值
不過上述的修改方式只適用于除斷言語(yǔ)句之外的截圖語(yǔ)句,如果在斷言語(yǔ)句的截圖中,雙擊進(jìn)入圖片編輯器,再修改里面的?threshold?,最終也是不會(huì)生效的。因?yàn)閿嘌哉Z(yǔ)句的闕值與其它截圖語(yǔ)句的闕值是不一樣的,它只能通過下述方式進(jìn)行設(shè)置:from airtest.core.setting import Settings as ST
ST.THRESHOLD_STRICT = 0.7
對(duì)于設(shè)備長(zhǎng)寬比不同、設(shè)備分辨率不同、多種字體的情況,我們也可以通過語(yǔ)法來提高兼容性。這種方式需要連接上腳本兼容性有問題的設(shè)備,把對(duì)應(yīng)截圖納入搜索列表。代碼腳本如下:picList = [pic1,pic2,pic3] # 截圖的圖片對(duì)象列表
for pic in picList:
pos = exists(pic)
if pos:
touch(pos)
break # 只要找到圖片列表中的任何一張圖片,就執(zhí)行touch
注意:如果 for 循環(huán)中沒有 break 語(yǔ)句,會(huì)導(dǎo)致次邏輯運(yùn)行時(shí)將所有的圖片都找一遍(找到后執(zhí)行 touch),而非找到合適結(jié)果立即返回。這種情況還適用于我們想點(diǎn)擊任意一個(gè)隨機(jī)圖標(biāo)的時(shí)候。如果同學(xué)們測(cè)試的項(xiàng)目可以使用 poco 框架,建議大家在自動(dòng)化腳本的時(shí)候,可以靈活混用 Airtest 和 Poco 腳本,以幫助同學(xué)們的腳本達(dá)成更好的兼容性:舉個(gè)例子,在網(wǎng)易云音樂的某個(gè)歌單中,想選擇前 10 首歌曲,如果用截圖腳本的話,需要編寫 10 條截圖腳本,但如果用 poco 框架的話,僅需要幾行遍歷節(jié)點(diǎn)的腳本(以選擇前 3 首歌曲為例):并且當(dāng)歌曲名稱變化時(shí),腳本截圖也需要跟著維護(hù);這時(shí)候選擇不變的節(jié)點(diǎn)作為操作對(duì)象,顯然可以提升我們腳本的兼容性。提升截圖腳本兼容性的技巧就整理到這里啦,當(dāng)然,除了上述技巧以外,同學(xué)們?cè)趯?shí)際的自動(dòng)化過程中,可能還會(huì)總結(jié)出其它的技巧。其實(shí)這些技巧都是在多次實(shí)操的過程中總結(jié)出來的,所以只要同學(xué)們多多實(shí)踐,就會(huì)有更多更好的解決問題的思路啦!