https://zhuanlan.zhihu.com/p/83373208
背景
由於各種新型號的移動終端層出不窮,爲滿足測試需要,公司投入測試的移動設備數量增長迅速,如何把散落在公司各個角落的移動設備有效的管理起來,提高資源利用率,如何快速適配各種品牌型號的終端設備,提升測試效率,如何能更快捷的接入自動化測試等,這些問題促就了知乎移動雲測平臺的誕生。
系統設計的主要目標在於提升知乎 App 的穩定性、優化用戶體驗、有效提升研發測試效率,主要功能如下:
- 設備管理:支持設備的自動接入,處理設備的使用申請。
- 遠程調試:通過 web 頁面在線進行單機控制或多機同步控制,提供設備屏幕實時畫面展示和系統日誌的展示。
- 自動化測試:支持兼容性自動化測試(Monkey)和 UI 功能自動化測試(Appium),提供自動化測試報告。
- 兼容性測試:安裝、覆蓋安裝、啓動、智能探索等 App 測試,觀察不同設備下 App 的穩定性和容錯性。
- 定向穩定性測試:在兼容性測試的基礎上長時間循環執行定向智能探索腳本等對 App 進行測試,觀察不同設備下 App 的穩定性。
架構
知乎雲測平臺從結構上主要分爲 web 前端、後端 server 和 agent client 三個部分:其中 web 前端專注於用戶交互和數據展示;後端 server 主要負責業務控制處理,包括設備註冊及狀態維護,指令下發,數據收集等功能;agent client 用於管理所搭載移動終端設備,包括設備信息上報,指令執行,測試報告數據回傳等功能。具體實現如下:
- web 前端
基於 React 實現,在顯示設計上採用阿里的 ICE 集成方案,ICE 一套基於 React 的中後臺應用解決方案,它提供了大量的可複用物料,包含了一條從設計端到開發端的完整鏈路,配套桌面工具能夠極速構建中後臺應用,即使在沒有 UI 設計支持的情況下, ICE 集成的內容也基本能滿足設計需求,因此我們選用了 ICE。 - 後端 server
基於 Spring Boot 框架進行開發,選用 Gradle 進行項目構建 ,集成了 Spring Data JPA、Spring Security OAuth 等組件,數據庫選用 MySQL;爲提升數據傳輸效率,我們 在 Spring Boot 中整合了 Netty 用於和 agent client 進行 Socket 通信,並選用了 Protobuf 做爲數據交換格式;在「設備遠程調試」功能的前後端交互設計上,我們選用了 WebSocket 協議,通過後端數據推送的方式,以保證設備操作的實時性,相較於需要使用推送實時數據到客戶端甚至通過維護兩個 HTTP 連接來模擬全雙工連接的舊的輪詢或長輪詢(Comet)來說,使用 WebSocket 可以極大的減少不必要的網絡流量與延遲。 - agent client
使用 Java 進行開發,最終以 jar 包的形式部署在 PC 機上,分別通過 adb 和 libimobiledevice 管理 PC 上掛載的 Android 設備 和 IOS 設備,設備掛載方式支持 USB 或 WiFi;在設備遠程調試功能實現上,針對 Android 設備和 IOS 設備分別採用了不同的解決方案,我們使用了 STF(Smartphone Test Farm) 提供的開源工具 Minicap 和 Minitouch,用於 Android 設備的屏幕截圖和指令運行,使用 STF 的 iOS Minicap 和 Facebook 的 WebDriverAgent 框架,用於 iOS 設備的屏幕截圖和指令運行,屏幕截圖即作爲設備遠程監控頁面渲染的圖片流來源;UI 功能自動化測試方案採用 Appium 開源工具進行實現,穩定性自動化測試方案其中 Android 設備採用自帶的命令行工具 Monkey 實現,iOS 設備則通過程序隨機生成指令進行測試。
功能介紹
- 設備管理
移動設備以 USB 的接連方式掛載在部署有 agent client 的 PC 上,設備的機序列號、系統類型、系統版本、品牌、型號、 屏幕分辨率等信息會通過 agent 上報給後端 server,設備序列號作爲設備唯一標識,進行設備信息的註冊或更新操作。設備信息註冊成功後,server 端負責維護設備在線狀態,當設備離線時,由 agent 端進行狀態上報給 server 端,server 端將對應設備狀態修改爲離線。前端頁面上可以查看當前接入的所有手機設備信息及在線狀態。
- 設備租借
對公司測試機進行統一登記管理,提供測試機租借服務,用戶可通過平臺的「設備租借」頁面,查找需要的設備,並進行發起租借操作,待設備持有人同意租借後,即可領取測試機設備。
- 設備遠程調試
設備遠程調試功能支持通過前端頁面進行遠程控制設備的應用安裝、啓動、卸載以及常規的點擊、長按、滑動等操作。
前端頁面上提供一個設備屏幕等比例縮放的圖片顯示區域,使用 <canvas> 標籤動態渲染從後端接收到的設備屏幕截圖,以此實現設備屏幕局的遠程監控功能。通過捕捉 <canvas> 的 onmousedown、onmousemove、onmouseover、onmouseout、onmouseup 等事件,並根據 <canvas> 控件的長高和光標當前座標換算出觸點在設備屏幕中的相對位置,最終在 agent 上根本系統平臺類型生成相應的操作指令,控制設備執行指令。
同時選中多個設備,操作首個設備,其他被選中的設備會同步執行當前操作,以達到多機同步控制的效果。
- 自動化測試任務創建
支持 Monkey 和 Appium 的自動化測試,通過前端頁面新建測試任務,配置相應的任務參數,任務創建成功後,由 server 端負責將任務下發給對應設備當前所掛載的 agent client,agent 收到任務即控制對應設備進行測試操作,並記錄測試任務結果數據最終返回給 server 端。
- 任務報告展示
後臺 server 會對接入的每個自動化測試任務的結果做統計彙總,並按照設備維度對任務的異常統計,截圖,日誌等信息進行展示,以快速定位測試中遇到的問題。
遠程控制界面畫質處理
由於需要實時操作處理,需要實時查看遠程設備的顯示並交互操作指令,指令數據是以 Json 的形式進行交互,只佔用很少的帶寬,而實時畫面顯示則需要將設備的實時畫面以圖片流的方式渲染到對應的 web 頁面上,那麼在使用時圖片的大小、網絡傳輸速度、渲染性能等都會影響使用體驗,其中可以主動優化的就是圖片大小,由於手動編譯的 stf 提供的 minicap,它本身也提供了圖片壓縮功能,如下是測試數據:
另外設備上圖片的顯示內容也會影響圖片的大小,像圖中這種留空比較多的圖片也不會特別大。實際使用中需要考慮網絡佔用上限以及使用體驗,調研發現設備實際使用過程中用戶比較關注的一般都是截圖和錄屏,而平臺單獨提供了高清的截圖和單獨的錄屏功能,所以對實時顯示的畫質沒有特殊要求,選取 5% 的壓縮比例在公司內網 2~3 M/S 的網絡速度下比較流暢,另外對流暢度優化還可以體現在圖片傳輸幀率上,可以按照一定的比例去掉中間的部分圖片,用戶使用過程中會感覺到圖片跳動渲染,類似 gif 圖片展示,由於已經選取了 5% 的壓縮比例,所以沒有做此優化。
遠程控制多機同步
在單機遠程控制上添加了多機功能,如圖中選取設備:
操作第一個設備時,指令同時分發到其他的設備上執行,如圖展示:
其他的設備界面也可以同時進行操作,這個地方處理主要通過 websocket 交互傳遞數據,在多機界面展示圖片流做了降幀處理,同時限制 10~20 臺的設備使用數量,在架構上用戶操作的指令主要由服務端對 agent 進行復制分發,過程如圖:
知乎移動端雲測試平臺實踐(二)—— Agent 設計和實現
背景
在雲測試平臺設計中,Agent 的設計一般來講需要考慮如下一些場景:
- 移動設備的交互控制是否需要 PC 設備的支持
和移動端設備進行數據交互,主要有兩種方式,一是通過常規官方建議的 PC - Mobile 的調試方式,使用公共協議如:adb、usbmuxd 進行數據交互,二是直接在 Mobile 中植入代碼,通過代碼調用系統 API 和服務端進行交互,省去 PC 的中轉環節
- 移動設備在測試任務執行上如何隔離
設備在使用過程中還需要考慮到它會執行哪個 APP 、哪一種類型的 APP、哪一組人員、哪一種測試類型等的業務測試,所以在設計時需要考慮單個設備的「原子性」
- 設備如何做到動態運維和自動化程度
設備的維護對於服務端來講一般都會以設備池的方式運行,這樣就需要考慮到增加、刪除設備對設備池帶來的影響,同時如果設備的維護在公共實驗室或者在遠端的機房,那對應的操作就需要遠程完成,所以設備的維護、重置、監控等相關的操作也需要提供遠程 API
- 自動化框架選擇和運行環境
自動化測試是雲測試的主要目的,自動化框架的選擇會影響自動化測試能力的擴展範圍,所以需要選擇一款合適的「基礎」自動化測試框架
系統選型
知乎雲測平臺採用利用 PC 作爲維護移動設備的服務器,交互模式爲服務端 - PC 端 - 移動設備交互的方式,PC 端部署與服務端進行交互的 agent 代碼,採用 socket 進行通信確保即時性,同時通過 http 主動消費服務端維護的任務池,執行完畢之後返回數據並循環進行,在自動化任務執行上採用 Appium 做爲「基礎」自動化測試框架。系統選型主要基於如下幾點:
- 大部分自動化框架的運行都基於 Mobile 掛載 USB 對應的 PC 上,同時 Agent 服務、自動化框架、硬件運維、異常處理等都需要穩定的 PC 運行環境
- Netty Socket 框架可以提供穩定的即時數據交互
- 任務數據的處理在精度上要求更高,所以採用 Http 請求任務池的方式
- 自動化框架選取在各方面都具有一定優勢的 Appium,「主要是社區比較活躍」,同時設備執行測試任務的隔離也主要由 Appium 來進行控制,如下是對比圖:
Agent 模塊組成
Agent 模塊在雲測試平臺中主要負責設備控制、維護的功能,主要包括三大模塊如下:
實時任務
基於 Netty Socket
實時交互如下圖展示:
移動端設備控制
在這裏移動端設備控制是方便使用者可以在遠端通過一定的方式遠程控制設備的操作,同時看到設備的實時顯示畫面,經過各種調研、測試、實驗選取 openstf [https://github.com/openstf/stf] 開源的兩款工具 minicap / minitouch 來完成這部分功能。stf 是一款可以遠程調試移動手機、手錶、Pad 的 web 工具,使用效果如圖:
參考 stf 的 nodejs 源碼中 minicap / minitouch 這兩款工具的使用方式,由於 Agent 平臺使用 java / kotlin 編寫,而 minicap / minitouch 是用 c/c++ 編寫,所以採用將手動編譯完成的 minicap / minitouch 運行程序內置到 Agent 中提供調用。
minicap
github 地址: https://github.com/openstf/minicap
當設備接入時 minicap 初始化線程會分爲如下幾個步驟對設備初始化和啓動:
minitouch
github 地址: https://github.com/openstf/minitouch
當設備接入時 minitouch 初始化線程也會分爲如下幾個步驟對設備進行初始化:
Agent minitouch / minicap 和 pc 交互圖如下:
定時任務
定時任務,主要是自動化測試任務的數據交互,雲測試平臺的優勢在於可以動態的調用多個設備進行測試,而每個設備的運行又是獨立的,所以任務的運行設計最小粒度以單個設備運行爲準,那麼無論是兼容性測試、安裝測試、自動化腳本測試、性能測試等都會在服務端拆爲單個的任務,以任務池的方式存放到多維隊列中,Agent 只需要在交互時拿到對應設備的隊列任務運行即可。與設備遠程控制要求交互的即時性不一樣,遠程控制要求指令必須在毫秒級以內完成數據的下發和返回,自動化任務交互可以容忍一定的延遲,所以在與服務端交互上採用了 Http 輪詢方式:
Http 輪詢
輪詢的詳細過程如下圖示:
設備維護
Agent 部署完成之後,會主動監聽當前 adb / usb 的設備連接狀態,當有新的設備接入、已有設備移除時會執行圖中的相應步驟來維護設備的連接狀態,做到移動設備的自動化接入和移除。
同時在設備的任務執行、遠程控制、離線上線等過程中都會和服務端進行數據維護交互,同步設備的狀態到服務端,爲服務端的任務處理、排隊策略、動態任務分配等提供判斷依據
遇到的問題和處理
1. minicap / minitouch 設備兼容問題?
由於後面設備類型的未知性,只是在 Agent 內部對指定的機型設備做了特殊兼容處理,除了幾款 stf 天然不支持的設備類型,並未發現有大量的兼容問題。
2. 設備圖片傳輸實時性問題?
目前大部分任務處理都是在公司內網環境,目前只是做了圖片數據級的壓縮,可以預見在網絡環境較差的情況下,可能需要圖片像素級的壓縮處理。
圖片處理是遠端控制的重要環節,主要處理方式如下:
我們從目前比較主流移動設備拿到的單個圖片的大小應該在 1M 左右,如果是高分辨率的設備或者 iPad、AndroidPad 等設備可能會更大,做純數據壓縮最多隻能做到百 KB 大小的級別。
在上面的前提下,我們可以犧牲一部分圖片的清晰度來換取操作的流暢度和網絡性能,如圖所示我們先將原圖按照比例等比壓縮到一定大小,然後將壓縮後的圖片在頁面上渲染到和設備同樣大小,
這樣丟失的清晰度和壓縮的比例有直接關係,在數據傳輸的過程中可以根據網絡質量的好壞動態修改圖片壓縮的比例。
經過圖片壓縮和數據壓縮,圖片的傳輸量級可以縮小到十 KB 大小的級別,經過調整大部分設備圖片數據的大小傳遞都在 20 KB 上下浮動,並且同時具有較好的清晰度。
3. 設備維護線程、自動化處理線程穩定性問題?
針對線程運行、本地環境不穩定,添加了一些頁面手動控制操作,當 Agent 運行過程中發現設備假死、卡頓、超時等問題會直接通過 IM 發送報警,運維可以通過頁面操作重新初始化設備相關線程及時發現和處理問題。
知乎移動端雲測試平臺實踐(三)—— 自動化測試方案設計和實現
背景
爲了充分利用雲測試平臺維護的設備,提升空閒設備使用率,開展自動化測試替代部分迴歸測試、重複性測試和多設備兼容測試,同時滿足如下幾種類型的自動化測試需求:
隨機測試(monkey、隨機操作指令):
在多設備執行的基礎上完成安裝、啓動、覆蓋安裝、monkey 測試 / 隨機指令、卸載等一系列操作。
遍歷測試(深度遍歷、智能探索):
在 monkey 測試 / 隨機指令的基礎上,對執行步驟進行改造,將隨機操作替換爲 app 內部頁面的深度遍歷,設計算法策略在一定程度上對被測 app 進行智能探索操作。
UI 自動化測試(appium):
在自動化測試框架支持的基礎上,提供多設備腳本運行能力,測試開發人員只需要編寫符合規則的測試腳本即可以在雲測試平臺上選擇多個設備進行測試,獲得測試結果。
在以上自動化測試的同時,測試報告中需要體現如下內容:
- 實時生成測試報告、測試結果數據
- 實時獲取設備的日誌並有對應的分析結果
- 可控的自動化測試過程
- 執行過程中設備頁面截圖或錄製視頻
- 測試結果中設備類型數據分析
在上面背景說明中,介紹了幾種測試類型需求,前兩種的設計流程比較簡單,也不需要外部人員的參與,第三種測試類型設計比較複雜,後續文章說明也以第三種測試類型爲主。
自動化執行框架設計
自動化框架
在
中自動化框架調研對比和各大雲測試平臺的使用,選擇了在各方面都具有一定優勢的自動化測試框架 appium 作爲自動化測試的執行控制層,本地啓動 appium hub 的方式接收腳本執行請求,這裏就不多加贅述了。
腳本語言和執行框架
雲測試平臺是由 Java + kotlin 開發,客戶端控制都是基於 Java 實現,這裏自然選擇 Java 作爲腳本語言,後續的腳本、流程說明也是以 Java 語言實現爲主,但是在腳本語言選擇上這裏不是強制要求,同樣可以選擇Ruby、Python、PHP,、JavaScript 和 C#,只是後續的實現需要平臺多做一步兼容而已。
在腳本執行方面沒有使用類似 junit、testng等第三方的運行框架,主要是爲了保持在運行過程中對腳本運行的控制和運行數據的交互,如下是腳本運行實現方案:
1.由平臺提供一定限制範圍的腳本編寫能力
主要是指運行過程的腳本編寫,以及如何提供類似截圖、步驟日誌、檢查點等公用方法,對於 Java 來說可以將一些公共的方法抽象出來放到腳本的父對象中,通過繼承將腳本編寫能力賦予給腳本本身,Python 也可以統一一個標準的類庫,通過引入的方式使用。
2.運行時由 agent 動態編譯編寫完成的腳本,反射實例化腳本對象
運行時處理腳本需要區分動態語言和非動態語言,還是以 Java、Python 爲例,由於沒有借用第三方的測試框架,觸發腳本運行對於 Java 來說需要進行編譯,也就是標題中說到的動態編譯,然後通過反射實例化對象運行,這裏有兩個要求,首先腳本編寫需要在雲測試平臺限定的包內,其次腳本運行、繼承的方法需要符合約定的規則。對於 Python 來說先將腳本內容以 IO 的方式寫到內存中,然後反射通過字符串的形式,導入模塊、去模塊尋找約定函數執行。
3.使用反射實例對象運行腳本,並調用實例中的方法和腳本進行數據、強控制交互
實例化腳本後開始運行腳本,運行前需要將所需要的運行資料注入到實例中,例如: appium 的 appiumDriver,運行同時可以隨時調用實例化對象中的約定方法對腳本運行進行控制,比如獲取執行步驟、日誌、圖片,傳遞參數,控制腳本暫停、運行、停止等交互,這也是爲什麼沒有使用一些第三方框架來觸發測試的原因。
通過上述過程基本上實現了用例到執行的基本過程,如圖:
也就是說只要提供了符合規範的腳本,就可以利用框架的通用性將腳本運行在任何 appium 支持的設備上,在架構上也剝離了自動化測試最關鍵的工作部分即:腳本編寫,也爲腳本管理、數據模板結合等用例的功能豐富提供更多可能性。
流程設計
如下是腳本自動化測試完整的業務執行方案:
自動化測試 UI 代碼以 git 工程的方式託管在公司的 git 服務器上,在工程基礎上編寫腳本,調試腳本通過之後合併入 git 工程,在 gitlab 上每一個腳本都會有一個唯一的地址,通過這個地址可以獲取到指定腳本,然後通過接口 / 表單的方式提交腳本運行測試,運行完成得到質量報告。
值得說明一下的是,在自動化測試過程中,公共方法、selenium / appium 公共 page object 等腳本數據會隨着自動化測試的深入越發龐大,所以需要圖中的公共方法抽取過程,這樣帶來的好處是由於腳本的抽取、複用會使腳本的編寫效率會越來越快。
如下是腳本執行流程結構圖,包含腳本執行的流程和結果收集:
腳本執行數據、執行交互設計方案:
這裏主要體現的是腳本和運行平臺間的數據交互、執行能力交互,比如腳本執行時需要使用到 appium 的 driver,而這個 driver 是通過平臺的設備參數來決定的,在運行時平臺動態生成 driver 然後通過協議類的方式注入 driver 到腳本內部,運行過程中通過協議類的停止、暫停、等待、銷燬等方法進行控制,運行完成後通過協議類獲取到運行結果。在腳本需要一些特定的功能時,也可以通過協議類引入接口方法,然後運行平臺通過接口代理的方式動態注入實現類的方式實現。
在實施的過程中發現有兩個難點,主要如下:
- 類和第三方包引用管理引起的腳本編譯問題
在自動化測試腳本編寫過程中,不可避免需要使用一些引入包,比如一些方便的工具類使用包等,對於 JAVA 腳本來講更新類、包引入等都需要重新編譯部署纔可以運行使用,測試平臺不可能會因爲腳本類、包的變化重新編譯部署平臺,而腳本的編寫絕大部分都是類引入的變化,包引入變化的比例很小,所以在類的變化上使用 Java 動態編譯技術解決類的動態引入,第三方的包引入更新則通過平臺工程的發版提前引入這些包升級完成。 - 協議類和包更新的自動化更新過程
在雲平臺和腳本工程中間是通過協議類進行數據交互,而定義的這個協議類和包發生之後按照上面的方案來說是需要雲平臺重新部署纔可以的,在實踐中發現腳本的能力建設和擴展等都需要通過協議類的修改才能實現,這就決定了這個協議類會頻繁的發生變更,所以 Agent 工程中在動態編譯前,手動校驗了服務器上的協議類版本,如果發現了新版則下載新版的協議類 jar,在動態編譯時替換到 -classpath 的協議類版本參數,這樣就做到了指定協議類內容的動態更新和自動化部署。
腳本設計
在上面提到過 「對於 Java 來說可以將一些公共的方法抽象出來放到腳本的父對象中,通過繼承將腳本編寫能力賦予給腳本本身」,所以腳本設計分兩個模塊:
協議父對象實現
如圖所示父對象中提供了測試驅動 androidDriver、log 日誌、checkPoint 檢查點、img 截圖等腳本能力
用例子對象編寫
如圖所示,實際的腳本繼承父對象的能力之後,可以完成編寫相關頁面測試邏輯、業務邏輯的自動化測試任務
腳本調試和運行
平臺腳本調試可以通過如下兩種方式進行:
本地調試
自行使用 main 方法、或者使用單元測試框架調試腳本通過
然後將主體修改爲規定格式的自動化腳本,視情況修改 appiumDriver 引入方式、添加日誌記錄、截圖、檢查點等
遠程調試
遠程調試需要在雲測試平臺上申請一臺使用設備如圖:
點擊圖中的按鈕,將腳本粘入運行,如下圖:
測試報告展示
報告主要分爲如下幾個部分
測試基本信息
主要展示測試過程的 app 基礎信息和測試相關的一些信息展示,概況展示腳本所有檢查點的通過比例,腳本運行的設備、通過、失敗的數據統計,運行概況展示每一個腳本在每一個設備上運行的過程和結果,以腳本和設備爲維度,log 鏈接中會展示詳細的腳本運行步驟日誌
檢查點概況
腳本運行的核心結果,主要展示此次自動化測試過程中所有的測試結果
截圖/步驟/異常
在腳本運行結束後,通過反射的方式獲取到腳本用例的詳細數據,通過 「截圖/步驟/異常」細化展示每一次運行的步驟、圖片、和檢查結果
性能圖表、過程視頻
同時在腳本運行過程中也會通過 appium 框架功能實現設備的網絡上下行統計、
和
,然後渲染性能數據生成圖表並提供視頻回放腳本執行過程