提起 UI 自動化測試,老是會有人拋出不少疑問:php
......python
今天小編就在這裏跟你們分享下,本身對 UI 自動化測試的理解以及我司質量平臺正在搭建的分佈式平臺 DuLab 是怎樣實現批量運行 UI 自動化測試 Case 的。android
隨着不停的版本迭代,軟件新增功能變的愈來愈多,對測試資源的需求也變得愈來愈大,執行人工測試的時間愈來愈長。對於人工測試的依賴開始變得棘手,所以你們開始尋找解決方案,UI 自動化也應運而生。ios
UI 即 User Interface(用戶界面)的簡稱,UI 自動化作的事情就是模擬用戶行爲進行操做,完成對用戶界面的測試。這也就從本質上限制了它的使用場景:redis
因此在你開始以前,最好認識清楚哪些業務場景是能夠自動化的~數據庫
針對我司的業務現狀,肯定好預期效果。c#
與接口自動化測試思路相同,咱們在進行 UI 自動化測試時,每一個 Case 都是一個單獨的 TestCase,咱們將全部須要執行的 case 放在同一個 TestSuit 中,批量執行並生成聚合報告。設計模式
下面是小編本身從點到面一步步的思考歷程,從基本的移動設備遠程管理,case 編寫到 case 的維護,再到 lab 平臺的搭建:緩存
目前市面上有不少成熟的 UI 自動化工具,如appium,airtest,Sikuli等等,它們提供了很是便捷的錄製服務,咱們只須要在 idea 上拖拖拽拽,立刻就能夠生成一個簡單的 UI 自動化腳本,且咱們只須要將這些工具封裝的工具庫部署在咱們的電腦上就能夠屢次運行咱們編寫的 case 了。網絡
這裏咱們將分開剖析進行 UI 自動化用到的錄製器和執行器的原理:
解讀其源碼咱們發現這些工具其實底層的實現原理都基本相同,核心即爲:對移動設備的遠程控制,並將控制指令封裝爲可讀通用的語法。
其實咱們平常使用手機時,手機系統就是經過咱們點擊的屏幕座標,從最上層的 view 依次向下遍歷,直到找到該座標位置下能夠響應用戶行爲的 UI 控件,執行對應的響應代碼。
可是咱們在編寫 case 時,若是 case 中記錄的全是在某個座標下對應的操做行爲的話,就會特別的晦澀難懂,且針對不一樣屏幕尺寸的設備也徹底不通用,這顯然是行不通的。
真實的用戶行爲其實無非就是,點擊了某個按鈕,滑動了某個頁面等等,主體其實就是 UI 控件,咱們在編寫 case 時也是同樣的,我但願的是對某個 UI 控件進行操做,那麼其實在執行 case 時,咱們徹底能夠獲取該 UI 控件在當前屏幕中的位置,再去調用底層的控制指令進行操做。
其實 case 錄製的原理就是上述執行原理的逆向思惟,咱們能夠在移動設備上開啓 server 服務,將移動設備的屏幕影像經過二進制流的形式實時傳輸給錄製器,將移動設備投屏到咱們的錄製器上。同時還須要實時獲取移動設備上的 UI Tree ,當咱們在錄製器上進行鼠標移動時,利用鼠標在屏幕上的座標信息從 UI tree 中遍歷對應的 UI 元素,並打印該元素的全部 UI 信息。
是否是感受很複雜,不用擔憂,已經有成熟的框架 Android Debug Bridge 和 WebDriverAgent 爲咱們提供了這些服務,下面👇會重點介紹的。
有興趣的同窗能夠自行 google。
這裏咱們直接選用網易的AirtestProject做爲咱們 UI 自動化的核心框架,緣由:
解決了 case 的錄製問題,下面咱們再來思考 case 的管理問題,在錄製 case 的過程當中咱們發現不少 case 都存在高度可複用模塊,如登陸模塊,可能咱們 80%的 case 中都進行了登陸操做,若某個版本中登陸頁面的 UI 發生了改動,致使元素的 path 發生了改變,這個時候咱們難道要找到全部設計到登陸的 case,逐個進行修改嗎?
其實在編寫 UI 自動化 case 時,咱們一樣也須要設計模式,參考業界優秀模式,再結合我司實際場景,整理的大致思路入下:
接入發佈平臺,定時輪訓獲取提測後的測試包和灰度包信息並落庫。 表結構以下:
CREATE TABLE `lab_package` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `version` varchar(32) CHARACTER SET utf8mb4 DEFAULT '' COMMENT '版本號', `buildVersion` varchar(32) CHARACTER SET utf8mb4 DEFAULT '' COMMENT '構建版本號', `bundleId` varchar(255) CHARACTER SET utf8mb4 DEFAULT '' COMMENT '包ID', `pkgPath` varchar(255) CHARACTER SET utf8mb4 DEFAULT '' COMMENT '包存儲路徑,能夠用來下載包體', `platform` varchar(255) DEFAULT NULL COMMENT '平臺 ios/android', `timestamp` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `branch` varchar(255) DEFAULT NULL COMMENT ' 所屬分支', PRIMARY KEY (`id`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=579001 DEFAULT CHARSET=utf8;
在 case 指定版本範圍時,從數據庫中查詢最新的符合要求的按照包地址(iOS 端存在多個不一樣 bundleId 的安裝包,須要先根據設備的 udid 獲取正確的 bundleId),而後下載安裝包並安裝到運行的設備上。
UI 自動化 case 運行時,最大的困擾是 UI 界面的變更。可是若是咱們接入 mock 平臺,保障 case 運行時的界面和 case 編寫時的界面以及數據是徹底相同的,那麼咱們在執行 case 時校驗驗證點,將會變的垂手可得。
前面咱們準備工做作好之後,就要考慮 case 運行的問題了。不一樣於接口自動化,UI 自動化依賴於真實的設備,可是設備資源是有限的,咱們在一臺 Mac 上運行時,根據 Mac 的性能,最多能夠同時控制幾臺設備,可是當咱們但願批量運行 case 時,可能須要在幾十臺甚至幾百臺設備上同時運行咱們的 UI 自動化 case。此時咱們就須要分佈式了,搭建一個手機 lab 集羣,由一臺 server 分配任務,多臺 worker 執行任務,遠程控制鏈接在該 worker 上的移動設備,最後再將全部的 report 報告進行聚合。
語言:python
核心框架:tornado+celery+redis
總體架構:
lab 主要分兩個模塊,server 調度服務,以及 worker 集羣。當 server 服務接收到用戶執行指令時,會去 case 倉庫遍歷符合用戶要求的 case 腳本,由 broker 中間件將任務分別分配給 worker 集羣,各 worker 任務執行結束後,會將每一個 case 的執行結果存儲到 result 結果集之中,待任務所有執行結束 server 會生成總的聚合報告,並將 report 報告經過飛書發送給用戶。
其中 worker 的總體架構以下:
當 worker 收到任務後,會開啓多進程在鏈接的移動設備上批量執行 UI 自動化 case,
值得一提的是,worker 中本地資源的管理,分別是對安裝包的管理和對 case 倉庫的管理;
case 倉庫實際上是 lab 項目的子模塊,測試人員在平常 case 的編寫和維護都是在 case 倉庫的項目中完成的,徹底不用關心 lab 項目的維護;當有測試同窗 push 代碼到遠程倉庫時,Jenkins 就會調用 server 服務的接口,由 server 服務通知各個 worker 更新 case 倉庫的代碼便可,保證 worker 在批量運行自動化 case 時,代碼是最新的;
安裝包的管理:有兩種形式,worker 服務除了天天定時獲取最新的安裝包列表緩存到本地外,當 case 執行時若本地安裝包沒法知足版本要求,worker 也會遍歷 app 安裝包的數據庫,將適合的安裝包緩存在本地並安裝到移動設備中;
由於咱們的 app 天天都在進行着不少的版本迭代,相應的咱們的 case 可能只能在部分版本區間中運行,那麼咱們此時就須要在 case 中限制版本區間,當 case 運行時,判讀設備中已安裝的 app 版本是否在該區間內,若不存在則下載安裝知足要求的版本到移動設備中再去執行 case;
更多更細節的設計這裏就再也不介紹了,有興趣的同窗留言探討哦~
文|crystal
關注得物技術,攜手走向技術的雲端