天天看點

小心!做 UI 自動化一定要跨過這些坑

導語 : “才剛寫完用例,怎麼開發大哥又改了UI了?” “維護這些破用例的時間,都夠我手工測三遍了,真的有意義麼?” “這破手機,能不能别老是系統彈框……”

UI自動化,在移動網際網路時代的今天,一直都是在各大測試社群最為火爆的一個TOPIC。甚至在測試同行面前一提起自動化,大家就會自然而然的問:“恩,你們是用的什麼架構?appium?還是robotium?”

其實在筆者看來,UI自動化是一個ROI較低的測試項(ROI即return on investment,中文意思是投資回報率)。但UI自動化相比接口自動化、白盒測試等,它更貼近手工業務測試行為。對于剛起步測試左移、效率提升的團隊來說,是最迅速的切入點,也是廣大黑盒tester,提升自身技術能力的起跑線。

筆者接觸UI自動化一年多,兼顧業務測試的同時斷斷續續地投入,曾經無數次的想放棄:

“才剛寫完用例,怎麼開發大哥又改了UI了?”

“維護這些破用例的時間,都夠我手工測三遍了,真的有意義麼?”

“測試架構自己有bug,我改用例也沒用啊……”

“我調試的時候這個用例還是通的,放到daily裡面跑就不通,到底怎麼回事嘛!”

“adb怎麼這麼不穩定啊,老是斷!!!”

“怎麼跑着跑着就crash了,到底是被測應用有問題,還是測試代碼有問題啊?”

“明明界面上有這個元素,怎麼就是查不到呢?”

“這破手機,能不能别老是系統彈框……”

“這手機真是渣,adb screencap截個圖,居然要三分鐘才傳回!”

“這些控件都沒有id,沒有text,層級還三天兩頭改,要我怎麼查……”

“查了這麼多論壇,怎麼就沒有人遇到過類似的問題呢?”

……

這些問題讓筆者一度懷疑,UI自動化這個TOPIC,是不是根本沒用,隻是tester為了漲薪,或者為了擺脫重複無聊的手工業務測試,而YY出來自我欺騙的。

筆者将以上所有的問題簡單分成三類:設計類,環境類,細節類。一個好的設計模式,能夠避免一部分問題;一套好的環境,可以讓我們從乏味的維護工作中解脫;精益求精的細節,讓測試用例更加可靠穩定。

小心!做 UI 自動化一定要跨過這些坑

圖一 UI自動化常見問題

填掉這三類坑,基本上就獲得了一套低成本高産出、少量維護、穩定可靠的UI自動化用例集。

這類問題,我們需要從根上治。UI自動化開發,也應該是嚴謹的開發工作,它也需要設計模式,也是磨刀不誤砍柴工。這裡的設計,主要包括選工具、架構分層等。很多前輩都分析過UI自動化各類工具的優缺點,對工具選用筆者不再贅述。主要依托uiautomator來介紹下筆者認為比較巧妙的用例架構設計。

無論你選擇appium、uiautomator、robotium還是espresso,剛入門時,看到的sample應該大緻都是這樣的。

小心!做 UI 自動化一定要跨過這些坑

圖二uiautomator和espresso邏輯樣例

問題在哪裡?這些sample過于簡單,都隻教了我們UI自動化三元素:怎麼查找元素、怎麼操作元素、怎麼校驗結果。如果我們按照大多數分享帖或GitHub sample來寫作自己的case。最後這種沒有任何設計模式的架構,肯定會面臨重構。拿上面的espresso來說:

假如action_save這個id開發改了,而你的用例集中,有30個步驟用例到了這個id,一個個去改,是不是要瘋?

不厭其煩的重複寫onView(withXX(xxx)).perform(click())這一長串,你不煩?

筆者是如何做的?分層設計和PageObjects模式。這兩個方法,基本解決了筆者遇到的圖一中所有的設計類問題。

小心!做 UI 自動化一定要跨過這些坑

圖三 架構設計建議

按照圖三進行分層設計後,得到如圖四的測試代碼包。

小心!做 UI 自動化一定要跨過這些坑

圖四 分層後的用例架構

PageObjects模式發源于selenium社群,它的目的是減少重複代碼,當開發修改UI時,測試隻需在有限的位置修改代碼。如果大家想深入了解PageObjects,請參照如下wiki:

https://github.com/SeleniumHQ/selenium/wiki/PageObjects

http://blog.csdn.net/kittyboy0001/article/details/25219053

我們來看一下,現在手管首頁Page包中的代碼和頁面。

小心!做 UI 自動化一定要跨過這些坑

圖五 手管首頁Page層部分代碼

回憶一下上面的google提供的sample,再對比引入分層設計和PO模式前後的代碼,點選圖五中的一鍵加速:

小心!做 UI 自動化一定要跨過這些坑

圖六 引入PO前後代碼對比

帶來的好處,當然不僅僅是業務用例代碼更清爽。

通過将查找和操作封裝到基礎層中,這部分代碼就具體業務無關了,即使拿到其他産品中也可以複用;

通過page層的分離,所有的與業務相關的id,text等都被限定在了page包中,哪怕開發改了UI,修改page包特定的頁面中對應的元素就好了。

對page包進行合理的業務拆分,比如将手管分成 MainPage(首頁),SoftwareManagerPage(軟體管理頁),WiFiManagerPage(WiFi管理頁)等,在開發改了某個具體業務的界面後,測試能夠迅速知道測試代碼需要改哪裡。

除了整個架構的設計,有時候一些小問題也可以經過巧妙設計。比如資源混淆的問題。

小心!做 UI 自動化一定要跨過這些坑

圖七 資源混淆

如圖七,在手機管家的釋出包中,用uiautomatorviewer dump下來發現,一鍵優化的button,其resource-id是o3,但其實開發coding時,定義的id顯然不會用這種沒有任何字面意義的代号,它在混淆之前叫optimize_button。

純黑盒的UI自動化,也許你會摒棄optimize_button,直接寫o3,但這樣顯然不夠科學,既帶來了嚴重的代碼可讀性問題,同時一旦版本疊代,混淆變了,o3也許就變成了o4。或者你會讓開發給你測試的包,不要混淆,但如果想用UI自動化測試已釋出的apk呢?

=解決該問題,也得從PageObjects說起。回到圖五中OPTIMIZE_BTN的定義,這個靜态變量并未在page中初始化,隻有一個@FindBy的注解。其實,在架構層驅動測試開始前,架構會先調用如下圖八所示的setAllField來初始化所有的page頁面。

如果被測應用未混淆資源,該方法隻是将@FindBy中的值指派給Field。

如果被測應用已混淆資源,該方法則會從mObfuscationMap(未貼出全部代碼,實際是解析一個開發提供的混淆表,以原始id為key,混淆id為value的HashMap)中讀出對應的id對應關系,将混淆後的id指派給Field。

小心!做 UI 自動化一定要跨過這些坑

圖八 Page層動态初始化

“這手機真是渣,adb screencap截個圖,居然要三分鐘才傳回!”……

引子中提到的這些問題,根據經驗,多半你的環境執行環境還不夠穩定。

已知的ADB不穩定原因如:電壓不穩,各類手機助手的幹擾,系統版本與ADB版本不比對、ADBcrash等等。如果我們迎難而上,去重寫ADB,投入将無限擴大。是以建議主要的解決方案,還是盡量規避。

a) 選用可靠硬體規避電壓不穩定,github上的STF項目組有過成熟的經驗,選用性能更優的USB分接器,電壓和可靠性會有更穩定的表現。(附上連結,wiki Recommended hardware一節中有不同硬體詳細的性能對比,https://github.com/openstf/stf )

b) 屏蔽各類手機助手的幹擾。91助手、豌豆莢等,基本都在adb上做了二次開發,它們會與原生adb間有相容性問題。建議直接使用Linux/MAC系統作為運作環境以屏蔽這類幹擾。

c) 降低用例在執行過程中對環境的依賴。Appium這類自動化工具,每一個測試步驟都需要PC端的appium server和測試手機端的bootstrap互動消息。測試過程中隻要USB連接配接不穩定,都會導緻整個測試套的失敗。是以筆者認為,使用更原生的uiautomator會是更好的選擇;同時,測試過程中的日志、截圖等,也盡量在測試手機上做持久化。

權限彈框,是手管UI自動化中的一個大坑。如下圖,是測試手管過程中,在華為手機上遇到的部分權限彈框。這些彈框,并不會用例每次執行都彈出,不同廠商的彈出框也不一緻。顯然點選彈框的邏輯,寫在case邏輯中,隻會導緻自動化變得更複雜更不穩定。

小心!做 UI 自動化一定要跨過這些坑

圖九 各類權限彈框

uiautomator的watcher,能夠完全實作點選彈框和用例邏輯的解耦。目前筆者的實作邏輯是,監聽彈框上的某個控件,當該控件出現時,執行action來點選掉其中的取消或确定按鈕。這樣,用例就隻需關注業務邏輯,而任何時候的彈框,都由watcher來自動點選。如下圖中,checkForCondition關注條件,action是操作。

小心!做 UI 自動化一定要跨過這些坑

圖十查找型Watcher

将所有的watcher分不同的手機廠商進行注冊後,再調用runWatchers(),然後再執行用例。該方法可以在@BeforeClass中或者RunListener的testRunStarted中調用。當然,如果某個用例不想某個具體的彈框被watcher點選掉,也可以調用removeWatcher()反注冊。

小心!做 UI 自動化一定要跨過這些坑

圖十一 注冊監聽器

Watcher并不能解決所有的彈框問題。例如,在開啟WiFi的場景中,由于WifiManager的setWifiEnabled和UI上的彈框點選是同步的(意思是調用了setWifiEnabled之後,如果界面上不點允許,該方法是不會傳回的),使用上面的watcher方式并不會點選WiFi權限申請的允許。這時,就需要用到線程方式來解決(如下圖十二),調用setWifiEnabled前,先啟動一個線程等待彈框彈出。

小心!做 UI 自動化一定要跨過這些坑

圖十二 多線程方式點掉彈框

出現上述問題,多半是因為我們的用例細節不夠嚴謹。這類問題,往往決定着我們自動化用例集,是不是能從90%的case通過率,提升到100%。

自動化相比手工,它隻會關注code告訴它的驗證點,是以選擇邏輯在用例中應該是禁用的。如下圖十三中右側的case,如果用例執行到if中,也許else流程中存在BUG,反之亦然。此時考慮拆分用例,左側才是理想的用例邏輯。

小心!做 UI 自動化一定要跨過這些坑

圖十三用例邏輯

另外,寫作case時,一定要牢記,隻有我們告知程式要assert,它才會去assert。查找,操作,斷言,UI自動化三要素缺一不可。

在testng中,會提供dependsOnMethods注解,似乎在鼓勵寫作用例時,使用用例間依賴。但筆者認為,用例間的依賴,會帶來不必要的維護成本。隻有高度解耦的用例邏輯,才能夠更加健壯的支撐用例執行順序調整、用例增删、出現異常場景後,A用例失敗不會導緻B用例也失敗。

有時候會遇到以下場景,雖然原生的自動化工具提供了等待元素可見的方法,但使用起來,還是無法真正等到元素可見。針對這個問題,如下圖的waitCondition方法是一個不錯的方案,它相對于thread.sleep來說,更節省時間。

小心!做 UI 自動化一定要跨過這些坑

圖十四反複等待方法

絕對坐标點選,在不同尺寸螢幕上無法相容。

第一方案應該是,推動開發對需要用到的控件添加ID或Accessibility。但根據經驗還是會有一些場景需要用到坐标點選:

1, 考慮投入産出比,為所有控件添加id的成本過高;

2, 動态布局添加的ID都一樣;

3, 存在非xml布局的界面(代碼中直接布局)。

這時,筆者依然不建議mDevice.click(100,200)這樣的坐标點選。有以下兩種值得一試的方案。

a) 找到相鄰控件坐标,計算目前控件的絕對坐标。如下圖十四,uiautomatorviewer中點選右上角警告小三角,會得到有一些元素(黃色控件),是可能無法找到的。而使用相對坐标就是說,我們可以擷取它相鄰控件的坐标,然後減去或加上一個比較小的px值,再點選計算後的坐标即可。

小心!做 UI 自動化一定要跨過這些坑

圖十五 相對坐标

b) 使用螢幕尺寸計算相對位置。在測試開始,将螢幕尺寸存下來,使用百分比的方式計算得到需要點選的位置。如下,點選【50%寬度,80%高度】的位置。

小心!做 UI 自動化一定要跨過這些坑

UI自動化測試是一門學起來很簡單,用起來很麻煩的測試技術。

想要入門,兩周就可以了解清楚uiautomator或espresso這類工具。UI自動化,無非就是查找元素、操作元素或裝置、驗證結果。這三個步驟循環多次,就是一個用例。

但要用好,并産出能效,需要走的路其實很長。由于篇幅限制和知識有限,這裡不可能把所有的問題一一列出。對于所有這些問題,無非兩個思路:一是繞過,二是解決。

選一個盡量簡化,盡量底層的工具(uiautomator或espresso),從根上繞過一些工具會存在的問題;

采用良好的設計模式,讓自己的架構更穩定,生命周期更長,維護成本更低;

明知道會耗費很多時間精力,收效卻很小的環境問題,盡量繞過;

優化用例邏輯和細節,使之穩定可靠,更能說服别人相信自動化的測試結論。

最後,祝願大家在UI自動化的道路上越走越順!

文章來源于:騰訊移動品質中心 TMQ