得物技術分佈式 UI 自動化實踐

前言

提起 UI 自動化測試,老是會有人拋出不少疑問:php

  1. UI 自動化能帶來什麼價值嗎?仍是在浪費時間?
  2. UI 自動化測試在整個測試流程中扮演什麼樣的角色?
  3. 有編寫 UI 自動化測試的時間,我早就完成業務測試了,我爲何還要編寫自動化測試的 case 呢?
  4. 針對於 UI 界面常常變更的業務場景,編寫和維護自動化 Case 簡直太難了,怎麼樣才能解決這些問題呢?

......python

今天小編就在這裏跟你們分享下,本身對 UI 自動化測試的理解以及我司質量平臺正在搭建的分佈式平臺 DuLab 是怎樣實現批量運行 UI 自動化測試 Case 的。android

爲何要作 UI 自動化?

隨着不停的版本迭代,軟件新增功能變的愈來愈多,對測試資源的需求也變得愈來愈大,執行人工測試的時間愈來愈長。對於人工測試的依賴開始變得棘手,所以你們開始尋找解決方案,UI 自動化也應運而生。ios

人工測試的弊端

  • 人工迴歸測試須要花費很長時間才能完成,很小的延遲就會讓發佈面臨風險。
  • 發佈節奏受到人工迴歸測試的限制。兩天以上的人工迴歸測試意味着最好的狀況下可以一個月發佈兩次。並且,開發者須要一次性發布全部東西。要麼所有發佈,要麼什麼都發布不了,由於須要將全部東西一塊兒測試。

UI 自動化測試的優勢

  • 解放了測試團隊針對臨時的和探索性案例的測試時間;
  • 能夠一邊開發一邊進行迴歸測試,減小等待時間;
  • 可重複性使用,快速進行迴歸測試;
  • 更好的利用資源(周未/晚上的資源空閒時段)。

UI 自動化的特色

UI 即 User Interface(用戶界面)的簡稱,UI 自動化作的事情就是模擬用戶行爲進行操做,完成對用戶界面的測試。這也就從本質上限制了它的使用場景:redis

  • 軟件需求變更不頻繁
  • 產品更新維護週期長
  • 比較頻繁的迴歸測試
  • 自動化測試腳本可重複使用

因此在你開始以前,最好認識清楚哪些業務場景是能夠自動化的~數據庫

預期效果

針對我司的業務現狀,肯定好預期效果。c#

  • 兼容性測試:針對市場上經常使用機型與系統版本,進行下載安裝使用,以發現兼容性故障,進而修復。
  • 埋點測試:校驗埋點數據是否正常上報,有無漏報,錯報,多報。
  • 迴歸測試:版本迭代中,進行迴歸測試保障代碼改動不會致使其餘場景產生故障。
  • 測試階段性能收集:在測試階段爲自動化 case 指定優先級,按照優先級運行自動化 case,提供更多的性能數據。

思路

與接口自動化測試思路相同,咱們在進行 UI 自動化測試時,每一個 Case 都是一個單獨的 TestCase,咱們將全部須要執行的 case 放在同一個 TestSuit 中,批量執行並生成聚合報告。設計模式

難點

  • 不一樣於接口自動化,單個客戶端設備某個時刻僅支持運行一個自動化 Case;
  • 受制於電腦性能,沒法在單一電腦設備上同時控制數十臺移動設備;
  • 隨着版本迭代,部分 Case 僅適用於某些 APP 版本,需限制版本範圍;
  • 沒法省略前置步驟,比方說想要對某個頁面進行 UI 自動化,沒法直接進入該頁面,要從啓動 APP 開始,選擇前置路徑才能進入指定頁面;
  • 相同場景下數據可能會發生變化,使得校驗規則沒法統一;
  • 不一樣帳號下,數據不一樣,可能會致使不少場景沒法測試;
  • 對各類系統各類型號的移動設備,進行遠程控制;
  • 如何在 UI 自動化的過程當中校驗埋點數據;
  • 大量的 AB 實驗,如何切換環境進行測試;
  • APP 安裝包的管理,如何選擇安裝包進行覆蓋安裝.
  • ......

架構

下面是小編本身從點到面一步步的思考歷程,從基本的移動設備遠程管理,case 編寫到 case 的維護,再到 lab 平臺的搭建:緩存

主流工具調研

目前市面上有不少成熟的 UI 自動化工具,如appium,airtest,Sikuli等等,它們提供了很是便捷的錄製服務,咱們只須要在 idea 上拖拖拽拽,立刻就能夠生成一個簡單的 UI 自動化腳本,且咱們只須要將這些工具封裝的工具庫部署在咱們的電腦上就能夠屢次運行咱們編寫的 case 了。網絡

這裏咱們將分開剖析進行 UI 自動化用到的錄製器和執行器的原理:

case 執行的原理

解讀其源碼咱們發現這些工具其實底層的實現原理都基本相同,核心即爲:對移動設備的遠程控制,並將控制指令封裝爲可讀通用的語法。

其實咱們平常使用手機時,手機系統就是經過咱們點擊的屏幕座標,從最上層的 view 依次向下遍歷,直到找到該座標位置下能夠響應用戶行爲的 UI 控件,執行對應的響應代碼。

可是咱們在編寫 case 時,若是 case 中記錄的全是在某個座標下對應的操做行爲的話,就會特別的晦澀難懂,且針對不一樣屏幕尺寸的設備也徹底不通用,這顯然是行不通的。

真實的用戶行爲其實無非就是,點擊了某個按鈕,滑動了某個頁面等等,主體其實就是 UI 控件,咱們在編寫 case 時也是同樣的,我但願的是對某個 UI 控件進行操做,那麼其實在執行 case 時,咱們徹底能夠獲取該 UI 控件在當前屏幕中的位置,再去調用底層的控制指令進行操做。

case 錄製的原理

其實 case 錄製的原理就是上述執行原理的逆向思惟,咱們能夠在移動設備上開啓 server 服務,將移動設備的屏幕影像經過二進制流的形式實時傳輸給錄製器,將移動設備投屏到咱們的錄製器上。同時還須要實時獲取移動設備上的 UI Tree ,當咱們在錄製器上進行鼠標移動時,利用鼠標在屏幕上的座標信息從 UI tree 中遍歷對應的 UI 元素,並打印該元素的全部 UI 信息。

是否是感受很複雜,不用擔憂,已經有成熟的框架 Android Debug Bridge 和 WebDriverAgent 爲咱們提供了這些服務,下面👇會重點介紹的。

與移動設備進行通訊的框架

有興趣的同窗能夠自行 google。

這裏咱們直接選用網易的AirtestProject做爲咱們 UI 自動化的核心框架,緣由:

  1. 提供了現成的腳本錄製工具 Airtest IDE;
  2. 除了經過 path 定位元素外,還參考Sikuli支持圖像識別定位 UI 元素;
  3. 相比於 Appium 移除了對 Java,JavaScript、Objective C、Java、Ruby、php、c#等語言的支持,更加輕量級;
  4. 提供了Airtest和Poco框架能夠在 python 項目中直接引用,也支持命令行一鍵執行;
  5. 提供了更加直觀的 report 報告。

Case 管理

解決了 case 的錄製問題,下面咱們再來思考 case 的管理問題,在錄製 case 的過程當中咱們發現不少 case 都存在高度可複用模塊,如登陸模塊,可能咱們 80%的 case 中都進行了登陸操做,若某個版本中登陸頁面的 UI 發生了改動,致使元素的 path 發生了改變,這個時候咱們難道要找到全部設計到登陸的 case,逐個進行修改嗎?

其實在編寫 UI 自動化 case 時,咱們一樣也須要設計模式,參考業界優秀模式,再結合我司實際場景,整理的大致思路入下:
上傳![

基礎層

  • 經常使用操做封裝:抽離重複代碼,進行封裝;
  • 工具類封裝:數據校驗,設備信息獲取,安裝包數據查詢,按照包下載等操做;
  • 埋點遍歷封裝:以單個頁面爲單位,獲取全部可點擊,可滑動,可編輯的 UI 元素,再模擬相應的用戶行爲;
  • 應用程序安裝卸載封裝:根據 udid 獲取各版本對應的安裝包,進行覆蓋安裝,或卸載安裝;
  • 系統設置封裝:切換環境,ab 實驗,網絡環境;
  • 版本選擇封裝:指定 case 運行的版本區間。

業務層

  • 頁面封裝:按照功能劃分,如評論相關操做,登陸相關操做等,將這些通用部分抽離並封裝,供全部測試 case 調用;
  • 模塊封裝:進入某個業務模塊的前置路基封裝等。

用例層

  • 測試用例集:按照業務分子文件夾,包含該業務的全部測試用例。

框架層

  • suit:存放用於組織不一樣用例集的 Suit 類;
  • report:生成單個 case 的 report 報告,和整個 suit 的聚合報告。

APP 安裝包管理

接入發佈平臺,定時輪訓獲取提測後的測試包和灰度包信息並落庫。 表結構以下:

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),而後下載安裝包並安裝到運行的設備上。

接入 mock 平臺

UI 自動化 case 運行時,最大的困擾是 UI 界面的變更。可是若是咱們接入 mock 平臺,保障 case 運行時的界面和 case 編寫時的界面以及數據是徹底相同的,那麼咱們在執行 case 時校驗驗證點,將會變的垂手可得。

分佈式

前面咱們準備工做作好之後,就要考慮 case 運行的問題了。不一樣於接口自動化,UI 自動化依賴於真實的設備,可是設備資源是有限的,咱們在一臺 Mac 上運行時,根據 Mac 的性能,最多能夠同時控制幾臺設備,可是當咱們但願批量運行 case 時,可能須要在幾十臺甚至幾百臺設備上同時運行咱們的 UI 自動化 case。此時咱們就須要分佈式了,搭建一個手機 lab 集羣,由一臺 server 分配任務,多臺 worker 執行任務,遠程控制鏈接在該 worker 上的移動設備,最後再將全部的 report 報告進行聚合。

lab 框架

語言: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

關注得物技術,攜手走向技術的雲端

相關文章
相關標籤/搜索