iOS UI 自動(dòng)化測試原理以及在 Trip.com 的應(yīng)用實(shí)踐
前言
筆者入職 Trip.com 已滿一年,回顧這一年的工作歷程,約一半的時(shí)間都在做 UI 自動(dòng)化測試相關(guān)內(nèi)容。從而,筆者更深入地研究了 iOS 平臺(tái)下的自動(dòng)化測試技術(shù),目前也在負(fù)責(zé)部門 App 自動(dòng)化測試平臺(tái)的搭建和維護(hù)。故想借這篇文章一并將所踩過的坑以及學(xué)習(xí)到的技術(shù),系統(tǒng)且全面地整理出分享給大家。
本文的內(nèi)容大致如下:
- iOS/macOS UI 自動(dòng)化測試框架 XCUITest 原理詳解
- 基于 Web Service 的自動(dòng)化測試平臺(tái)架構(gòu)設(shè)計(jì)
- Appium 與 Macaca 介紹與對比
- Trip.com App UI 自動(dòng)化測試現(xiàn)狀
自動(dòng)化測試可以分為白盒測試、黑盒測試以及灰盒測試,本文主要圍繞 Apple 官方提供的 XCUITest 測試框架,逐步闡明 iOS 操作系統(tǒng)下的 UI 自動(dòng)化測試原理、架構(gòu)設(shè)計(jì)思想以及應(yīng)用場景。
XCUITest 原理詳解
iOS UI自動(dòng)化測試核心技術(shù)
2015 年,Apple 發(fā)布了 UI 自動(dòng)化測試框架 XCUITest 并集成在 Xcode7 中,而 iOS/macOS UI 自動(dòng)化測試依賴兩個(gè)核心技術(shù):XCUITest 和 Accessibility。
XCUITest 是集成在 Xcode 中的測試框架,若想使用 UI 測試功能,可以在創(chuàng)建 iOS 項(xiàng)目時(shí)勾選 Include Tests 選項(xiàng),從而使項(xiàng)目具備自動(dòng)化測試的能力。而 Accessibility 技術(shù),則是 Apple 官方為視障用戶提供的一整套使用 iOS/macOS App 的解決方案。
Xcode 項(xiàng)目創(chuàng)建 UITests Target 并運(yùn)行測試,其編譯產(chǎn)物 Test App 本質(zhì)上是一個(gè) Deamon 守護(hù)進(jìn)程,該進(jìn)程有獨(dú)立的應(yīng)用程序生命周期,依靠 XCUIApplication 類型進(jìn)行管理。UITests 的 Test App 進(jìn)程在運(yùn)行時(shí)會(huì)驅(qū)動(dòng) Host App(項(xiàng)目的主 Target 產(chǎn)物),并且利用元素審查的相關(guān) API 驅(qū)動(dòng) Host App 模擬用戶行為交互,從而進(jìn)行 UI 自動(dòng)化測試。
對于 Accessibility 技術(shù),開發(fā)人員需要注意的是,XCUITest 框架默認(rèn)并不能將所有視圖元素審查到,只會(huì)審查到可以被 VoiceOver 功能讀取文字的元素。比如,UIButton 和 UILabel,這些視圖對于視障用戶而言可以通過語音來獲知其內(nèi)容,而對于 UIImageView、 UIView 這種對于視障人士并不友好的 UIKit 視圖元素默認(rèn)是不會(huì)審查到的,所以編碼時(shí)要另行配置 Accessibility 相關(guān)屬性,以保證其支持 Accessibility 從而在 UI 自動(dòng)化查詢的元素層級中可見。
基于 XCUITest 框架 和 Accessibility 技術(shù)的自動(dòng)化測試,有利于 App 進(jìn)行數(shù)據(jù)一致性校驗(yàn),但 UI 一致性校驗(yàn)?zāi)芰^弱。比如,App 可以針對某些數(shù)據(jù)請求結(jié)果或者某個(gè)元素是否存在進(jìn)行校驗(yàn),而視覺展示效果卻仍需要人工介入。
XCUITest 框架結(jié)構(gòu)
XCUITest 測試框架 API 主要包含:元素查詢(UI Element Queries)相關(guān)類型,如 XCUIElementQuery,UI 元素(UI Elements)相關(guān)類型,如 XCUIElement,以及測試 App 生命周期類型(Application Lifecycle)類型,如 XCUIApplication。
接下來,我們創(chuàng)建一個(gè)簡單 Demo 項(xiàng)目,來學(xué)習(xí)如何使用 XCUITest 框架編程,并進(jìn)行 iOS UI 自動(dòng)化測試。
利用 Xcode UITests Target 進(jìn)行自動(dòng)化測試
創(chuàng)建一個(gè) Demo 工程,勾選 Include Tests 選項(xiàng),在 ViewController 里編寫如下代碼。本文 Demo 工程可訪問鏈接 https://github.com/niyaoyao/UITestDemo 。
- import UIKit
- class ViewController: UIViewController {
- lazy var testImageView: UIImageView = {
- let testImageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
- testImageView.backgroundColor = .red
- testImageView.accessibilityIdentifier = "test imageview"
- return testImageView
- }()
- lazy var testLabel: UILabel = {
- let testLabel = UILabel(frame: CGRect(x: 0, y: 130, width: 100, height: 20))
- testLabel.backgroundColor = .green
- testLabel.text = "test label"
- return testLabel
- }()
- lazy var testView: UIView = {
- let testView = UIView(frame: CGRect(x: 0, y: 170, width: 100, height: 50))
- testView.backgroundColor = .blue
- testView.accessibilityIdentifier = "test view"
- return testView
- }()
- lazy var testButton: UIButton = {
- let testButton = UIButton(frame: CGRect(x: 0, y: 230, width: 100, height: 50))
- testButton.backgroundColor = .yellow
- testButton.setTitle("測試按鈕", for: .normal)
- return testButton
- }()
- override func viewDidLoad() {
- super.viewDidLoad()
- view.addSubview(testImageView)
- view.addSubview(testLabel)
- view.addSubview(testView)
- view.addSubview(testButton)
- }
- }
源碼解釋,上面的這段代碼創(chuàng)建了四個(gè)視圖實(shí)例,分別為 UIImageView、UILabel、UIView 和 UIButton 類型,并將四個(gè)視圖實(shí)例添加到當(dāng)前頁面中。其中,UILable 和 UIButton 僅設(shè)置了frame、字符串、背景顏色等屬性,但是對于 UIImageView 和 UIView 視圖除了一般的視圖屬性,還設(shè)置了 accessibilityIdentifier 個(gè)屬性是為了讓 UIImageView 和 UIView 支持 Accessibility 功能,但僅設(shè)置這個(gè)屬性并不能使這兩個(gè)視圖在 Accessibility 的元素層級結(jié)構(gòu)中可見。接下來就對 Accessibility 功能做簡要介紹。
讓 App 支持輔助功能
使用 Accessibility Inspector
前文中提到 Apple 對于視圖元素會(huì)默認(rèn)審查能夠通過 VoiceOver 播放文字的視圖元素,而對于 UIImageView、UIView 這種默認(rèn)不支持 Accessibility 功能的需要配置相關(guān)特性,而開發(fā)人員在開發(fā)過程中可以通過 Accessibility Inspector 查看不同進(jìn)程的 Accessibility 元素層級,該應(yīng)用可以審查 iOS 和 macOS 的元素。
選擇 Xcode 的圖標(biāo)菜單并選擇 Open Developer Tool 選項(xiàng),點(diǎn)擊 Accessibility Inspector 即可開始使用。
當(dāng)我們沒有設(shè)置 isAccessibilityElement 屬性時(shí),在 Accessibility 元素層級結(jié)構(gòu)中就無法看到 UIImageView 和 UIView 元素,只能看到 “test label” 和“測試按鈕”。而當(dāng)我們將 UIImageView 和 UIView 的 isAccessibilityElement 屬性設(shè)置為 true 時(shí), UIImageView 和 UIView 元素才能在元素層級中可見。
Accessibility 相關(guān)屬性
- UIAccessibility: var accessibilityLabel: String? { get set }
accessibilityLabel 屬性可以解決絕大部分的 Accessibility 問題,當(dāng)光標(biāo)將焦點(diǎn)放在設(shè)置該屬性的元素師時(shí),它的內(nèi)容可由 VoiceOver 讀取的人類可讀的字符串。但如果不是需要被視障用戶獲知的視圖元素,僅用于自動(dòng)化測試,就可以不用設(shè)置該屬性。
- UIAccessibility: var accessibilityIdentifier: String? { get set }
accessibilityIdentifier 屬性不會(huì)被 VoiceOver 誦讀,而是面向開發(fā)人員的字符串,可在不希望用戶操作 accessibilityLabel 的情況下使用。
- UIAccessibility: var isAccessibilityElement: Bool { get set }
如果 isAccessibilityElement 未設(shè)置為 true,那么這個(gè)視圖將不會(huì)在 Accessibility 視圖層次結(jié)構(gòu)中可見。
- The default value for this property is false unless the element is a standard UIKit control, in which case, the value is true. —— Apple Documentation
另外,根據(jù) Apple 官方中的介紹 UIControl 的子類的 isAccessibilityElement 屬性都默認(rèn)設(shè)置為 true。
手動(dòng)編寫測試 case
- import XCTest
- class UITestDemoUITests: XCTestCase {
- override func setUpWithError() throws {
- // ...
- }
- override func tearDownWithError() throws {
- // Put teardown code here. This method is called after the invocation of each test method in the class.
- }
- func testExample() throws {
- // UI tests must launch the application that they test.
- let app = XCUIApplication()
- app.launch()
- let label = app.staticTexts["test label"]
- XCTAssertTrue(label.exists)
- let button = app.buttons["測試按鈕"]
- XCTAssertTrue(button.exists)
- let imgview = app.images["test imageview"]
- XCTAssertTrue(imgview.exists)
- let view = app.otherElements["test view"]
- XCTAssertTrue(view.exists)
- // Use recording to get started writing UI tests.
- // Use XCTAssert and related functions to verify your tests produce the correct results.
- }
- func testLaunchPerformance() throws {
- if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 7.0, *) {
- // This measures how long it takes to launch your application.
- measure(metrics: [XCTApplicationLaunchMetric()]) {
- XCUIApplication().launch()
- }
- }
- }
- }
源碼解釋,XCUIApplication 類型的實(shí)例,是管理 Test App 生命周期的實(shí)例對象,可以通過該對象獲取 Accessibility 視圖層級結(jié)構(gòu),通過 XCTAssertTrue 斷言元素是否存在。
錄制交互行為自動(dòng)生成測試 case
對于相對復(fù)雜的 Test Case,可以通過 Xcode 提供的測試行為錄制功能進(jìn)行自動(dòng)代碼生成。
UITest 執(zhí)行過程
點(diǎn)擊 Test 定義的 function 前方對應(yīng)的播放按鈕或者 Test Navigator 中對應(yīng) function 的播放按鈕,就可以開始執(zhí)行 UI 測試。而開始 UI 測試后,會(huì)先執(zhí)行源碼編譯,將 Target 中的源碼編譯出產(chǎn)物,啟動(dòng) Test App 進(jìn)程,進(jìn)入 Test 程序執(zhí)行 app.launch() 則會(huì)啟動(dòng) App,然后執(zhí)行斷言源碼。
iOS 自動(dòng)化測試工具鏈
編寫了基本的 UI 測試的 UITest Target 方法之后,我們可以利用相關(guān)命令行工具鏈,將 iOS UI 自動(dòng)化測試腳本化,從而可以方便集成入 CI 流程。
xcodebuild
- xcodebuild test -project UITestDemo.xcodeproj -scheme UITestDemoUITests -destination 'platform=iOS,id=<iPhoneUDID>'
可以利用上述命令執(zhí)行自動(dòng)化測試,也可以將命令進(jìn)行拆分,拆分為測試編譯命令和測試執(zhí)行命令,以便細(xì)化自動(dòng)化測試過程。測試編譯命令:
- xcodebuild build-for-testing -project ****.xcodeproj -scheme **** -configuration Debug -sdk iphonesimulator -destination 'platform=iOS Simulator,id=XXXXX' -derivedDataPath ~/derived_path -quiet COMPILER_INDEX_STORE_ENABLE=NO GCC_WARN_INHIBIT_ALL_WARNINGS=YES | tee build.log
測試執(zhí)行命令:
- xcodebuild test-without-building -xctestrun ****.xctestrun -configuration Debug -sdk iphonesimulator -destination 'platform=iOS Simulator,id=XXXXXX' -derivedDataPath ~/derived_path -resultBundlePath ****.xcresult -only-testing:****-UITests/TargetTests
xcrun simctl
simctl 命令是 xcrun 的一套自命令,提供一系列用來控制 iOS 模擬器的命令。
列舉當(dāng)前已經(jīng)啟動(dòng)的模擬器 xcrun simctl list devices | grep booted
啟動(dòng)模擬器 xcrun simctl boot XXXXX
關(guān)閉模擬器 xcrun simctl shutdown XXXXX
設(shè)置模擬器權(quán)限 xcrun simctl privacy XXX grant location-always xx.xx.xxx
安裝 App xcrun simctl install {} {}'.format(uuid, app_path)
運(yùn)行指定 App xcrun simctl launch {} {}'.format(uuid, bundle_id)
結(jié)束指定 App xcrun simctl terminate {} {}'.format(uuid, bundle_id)
卸載指定 App xcrun simctl uninstall {} {}'.format(uuid, bundle_id)
ideviceinstaller
與控制模擬器相似,iOS 真機(jī)也有相應(yīng)的控制命令行工具鏈,例如 ideviceinstaller。
安裝 apppath 下的 app ideviceinstaller -i apppath
安裝 xxx.ipa 為應(yīng)用在本地的路徑ideviceinstaller -u [udid] -i [xxx.ipa]
卸載應(yīng)用 ideviceinstaller -u [udid] -U [bundleId]
查看設(shè)備安裝的第三方應(yīng)用 ideviceinstaller -u [udid] -l
同上,查看設(shè)備安裝的第三方應(yīng)用 ideviceinstaller -u [udid] -l -o list_user
查看設(shè)備安裝的系統(tǒng)應(yīng)用 ideviceinstaller -u [udid] -l -o list_system
查看設(shè)備安裝的所有應(yīng)用 ideviceinstaller -u [udid] -l -o list_all
列出手機(jī)上所有的用戶安裝的app ideviceinstaller -l
ios-deploy
查看當(dāng)前鏈接的設(shè)備 ios-deploy -c
安裝APP ios-deploy --[xxx.app]
卸載應(yīng)用 ios-deploy --id [udid] --uninstall_only --bundle_id [bundleId]
查看所有應(yīng)用 ios-deploy --id [udid] --list_bundle_id
查看應(yīng)用是否安裝 ios-deploy --id [udid] --exists --bundle_id
利用以上命令行工具鏈,就可將 UI 自動(dòng)化測試根據(jù)不同項(xiàng)目進(jìn)行自定義的腳本接入 CI 流程,比如接入 GitLab Pipelines 中,對 code review、 merge request 等過程進(jìn)行干預(yù)。
基于 Web Service 的架構(gòu)設(shè)計(jì)
App 自動(dòng)化測試平臺(tái)的架構(gòu)設(shè)計(jì)
從前文中我們了解到,我們可以利用 Xcode 創(chuàng)建 UITest Target,編寫 UITest Case 測試腳本,輔以 xcodebuild 等相關(guān)命令工具鏈編寫自動(dòng)化腳本,就能接入 CI/CD 流程,實(shí)現(xiàn) iOS App 的 UI 自動(dòng)化測試,從而達(dá)到釋放人力資源,降低人工測試的成本的目的。
但與此同時(shí),又有新的問題出現(xiàn),那就是業(yè)務(wù)頻繁的迭代的情況下,我們寫的 Test Case 腳本,很容易因?yàn)闃I(yè)務(wù)的改變而導(dǎo)致廢棄,測試腳本復(fù)用率低,又增加了開發(fā)成本。如果不同系統(tǒng)平臺(tái)的 App,如,Android、iOS 甚至 Web App 能共用一套測試腳本,提高腳本復(fù)用率,會(huì)降低開發(fā)成本,更有利于業(yè)務(wù)回歸。
除此之外,對于復(fù)雜業(yè)務(wù)的回歸測試,若希望提高大量測試 case 的業(yè)務(wù)回歸效率,必然要提高并發(fā)性,縮減測試時(shí)間。故在這樣的需求下, Facebook 團(tuán)隊(duì)就設(shè)計(jì)出了 Appium 這樣的基于 Web Service 的自動(dòng)化測試工具。類似 Appium 的測試工具還有阿里巴巴團(tuán)隊(duì)設(shè)計(jì)的 Macaca,這類測試工具的設(shè)計(jì)架構(gòu)如下圖可視。
基于 Web Service 的自動(dòng)化測試的架構(gòu)主要可以分為命令分發(fā)服務(wù) Web Service 模塊和 UI 測試驅(qū)動(dòng)模塊。
對于命令分發(fā)服務(wù)模塊,其任務(wù)是搭建通用測試 case 腳本與底層驅(qū)動(dòng)之間的通信橋梁,而 HTTP RESTful API 恰能滿足這樣跨平臺(tái)的需求。因此,Web Service 模塊需要搭建 HTTP Web Service 進(jìn)行命令轉(zhuǎn)發(fā),將自動(dòng)化測試中的 Test Case 腳本作為 Web Service 的 Client 端,向 Web Service 的 Server 端發(fā)送請求。而 Web Service 的 Server 接收到請求后,再將請求轉(zhuǎn)發(fā)到底層的 UI 測試的驅(qū)動(dòng)進(jìn)程,以便后續(xù)驅(qū)動(dòng) UI 測試。
對于 UI 測試驅(qū)動(dòng)模塊,其主要任務(wù)是,接收 Web Service Server 端轉(zhuǎn)發(fā)來的請求,并觸發(fā)驅(qū)動(dòng)進(jìn)程進(jìn)行 UI 自動(dòng)化測試,最終收集測試結(jié)果,并生成測試報(bào)告。Android 操作系統(tǒng)的底層驅(qū)動(dòng)一般是 UIAutomator 程序;而對于 iOS 系統(tǒng), Appium 用的是 WebDriverAgent,Macaca 是 XCTestWD。而不論 WebDriverAgent 還是 XCTestWD 都是一個(gè)基于 XCUITest 的 Xcode project,其技術(shù)核心也就是我們前文介紹的以 XCUITest 和 Accessibility 為基礎(chǔ)的 iOS UI 自動(dòng)化測試技術(shù)。
App 自動(dòng)化測試平臺(tái),需要先運(yùn)行 Web Service Server,Server 作為測試指令的發(fā)出者,向測試驅(qū)動(dòng)發(fā)出請求,從而驅(qū)動(dòng) Test App 進(jìn)程操作 App。因此,需要先在 Jenkins Slave 機(jī)器啟動(dòng)運(yùn)行 Web Service Server,例如,在本地 4722 端口創(chuàng)建 Web Service,并監(jiān)聽 Client 向該端口發(fā)送的請求,再轉(zhuǎn)發(fā)給驅(qū)動(dòng)層。
驅(qū)動(dòng)項(xiàng)目(WebDriverAgent 或 XCTestWD)編譯成功后,都會(huì)在運(yùn)行的設(shè)備上創(chuàng)建并運(yùn)行一個(gè) Runner 程序,該程序就是利用 XCUITest 編譯成 Test App,但與前文 Demo 不同的是,這個(gè)程序會(huì)在設(shè)備上也會(huì)創(chuàng)建一個(gè) Web Service,接收 Server 發(fā)來的請求,并根據(jù) Test App 中程序處理請求,最后返回響應(yīng)結(jié)果給 Server。
例如,創(chuàng)建測試 Session 過程,WebDriverAgent 編譯成功后會(huì)在測試設(shè)備的 8080 端口創(chuàng)建 Web Service,從而 Jenkins Slave 上運(yùn)行的 Web Service Server 能夠?qū)?Client 的請求轉(zhuǎn)發(fā)給 WebDriverAgent 創(chuàng)建的 Web Service,然后經(jīng)過 WebDriverAgent 的內(nèi)部路由/wd/hub/session 進(jìn)行映射,找到對應(yīng)創(chuàng)建 session 的具體代碼,保存 Session ID 值,并將 Session ID 作為響應(yīng)結(jié)果返回給 Jenkins 的 Web Server。其他測試操作如,查找 element、查找元素 value,滾動(dòng)某個(gè)元素等操作,這些操作 Jenkins 的 Web Service C/S 和底層驅(qū)動(dòng)間的通信過程,都與建立 Session 過程相類似。
所以,有了基于 Web Service 的 UI 自動(dòng)化測試工具,我們可以更加高效地進(jìn)行自動(dòng)化測試,復(fù)用性更高、可支持多平臺(tái),跨平臺(tái)測試,甚至可以利用其 Web Service 搭建分布式的測試平臺(tái),基于 Jenkins 服務(wù)的架構(gòu)設(shè)計(jì)如下圖所示。
根據(jù)上圖架構(gòu)設(shè)計(jì),我們可以利用多臺(tái)機(jī)器搭建 Jenkins 集群,根據(jù)我們 CI/CD 流程所需,向 Jenkins Server 發(fā)送請求,再由 Jenkins Server 分配不同 Jenkins Slave 執(zhí)行 Job,每個(gè) Jenkins Slave 都配置好 UI 自動(dòng)化測試平臺(tái)驅(qū)動(dòng)多臺(tái)設(shè)備進(jìn)行自動(dòng)化測試。從而實(shí)現(xiàn)分布式的自動(dòng)化測試平臺(tái),提高并發(fā)性、提升測試效率,縮減回歸測試的時(shí)間。
接下來就分別介紹 Appium 和 Macaca 的簡單使用。
Appium 工具鏈矩陣
WebDriverAgent
WDA 是 Facebook 基于 XCUITest 測試框架開發(fā)的 iOS UI 自動(dòng)測試 Driver。類比 Macaca Runner。
源碼安裝 WDA
- git clone https://github.com/appium/WebDriverAgent.git
真機(jī)測試修改 Team ID
選擇 Apple 開發(fā)賬號(hào)的 Team。
Appium Web Service Server
Appium Server 用于 HTTP 命令轉(zhuǎn)發(fā),驅(qū)動(dòng)底層 Driver WDA。
利用 Appium Desktop 啟動(dòng) Server
下載鏈接 https://github.com/appium/appium-desktop/releases/download/v1.21.0/Appium-mac-1.21.0.dmg
安裝 Appium App,并用 GUI App 啟動(dòng) Server。
利用 Appium Command 啟動(dòng) Server
安裝 Nodejs 依賴
執(zhí)行命令行
- npm install -g appium
啟動(dòng) Server
執(zhí)行命令行
- appium -a 127.0.0.1 -p 4722
參數(shù)列表:http://appium.io/docs/en/writing-running-appium/server-args/index.html
端口映射
執(zhí)行命令行
- iproxy [LOCAL_TCP_PORT] [DEVICE_TCP_PORT]
http://manpages.ubuntu.com/manpages//trusty/man1/iproxy.1.html
https://github.com/libimobiledevice/libusbmuxd/blob/master/tools/iproxy.c
端口映射關(guān)系
執(zhí)行命令行
- appium -a 127.0.0.1 -p 4722 --webdriveragent-port 8123
如果啟動(dòng) appium server 時(shí)設(shè)置了 WDA 的 Port 為 8123,則 iproxy 命令第一個(gè)入?yún)㈨毷潜镜乇O(jiān)聽端口可任意隨機(jī)選擇,第二個(gè)入?yún)⒈仨殞?yīng) appium 命令指定的 WDA 的端口,可如下執(zhí)行
- iproxy 8100 8123
驅(qū)動(dòng) Runner 存儲(chǔ)位置
全局安裝 appium server 到本地后,WebDriverAgent.xcodeproj 存儲(chǔ)在以下路徑中。
- /usr/local/lib/node_modules/appium/node_modules/appium-webdriveragent/WebDriverAgent.xcodeproj
Web Service Client —— Test Case
測試項(xiàng)目
https://github.com/appium/appium/tree/master/sample-code
javascript-webdriverio
安裝依賴
執(zhí)行命令行
- cd appium-master/sample-code/javascript-webdriverio
- npm install
修改配置
修改測試腳本中 capabilities 配置。
- const iosCaps = {
- platformName: 'iOS',
- automationName: 'XCUITest',
- deviceName: process.env.IOS_DEVICE_NAME || 'iPhone',
- udid: 'iphone udid',
- platformVersion: process.env.IOS_PLATFORM_VERSION || '13.6.1',
- noReset: true,
- bundleId: 'your app id',
- app: undefined // Will be added in tests
- };
capabilities 文檔 https://appium.io/docs/en/writing-running-appium/caps/
https://appium.io/docs/en/writing-running-appium/default-capabilities-arg/
運(yùn)行 Case
執(zhí)行命令行
- npm test
Macaca 工具鏈矩陣
與 Appium 相類似,Macaca 的工具鏈矩陣也包含 Driver、Web Service Server 和 Web Service Client。
安裝 Macaca 工具鏈
- # 本地安裝
- $ npm i macaca-ios --save-dev
- # 全局安裝
- $ npm i macaca-ios -g
- # 安裝有 TEAM_ID 的 macaca-ios
- $ DEVELOPMENT_TEAM_ID=TEAM_ID npm i macaca-ios -g
更多詳細(xì)安裝過程可參閱官方文檔 https://macacajs.github.io/zh/guide/environment-setup.html#%E5%AE%89%E8%A3%85-node-js
Appium 與 Macaca 的對比
框架名稱相同點(diǎn)不同點(diǎn)
我們的 UI 自動(dòng)化測試平臺(tái)最初僅接入 Macaca 框架,獨(dú)立維護(hù)一份倉庫以供內(nèi)部平臺(tái)使用。而維護(hù)過程中也會(huì)遇到各種問題并自行解決,驗(yàn)證無誤后也會(huì)反饋給官方,并提供相應(yīng)解決方案。目前也已開始逐步接入 Appium 框架對現(xiàn)有平臺(tái)進(jìn)行技術(shù)改造,以適應(yīng)更多場景,以及保障框架長期穩(wěn)定可持續(xù)地維護(hù)。
Trip.com App 自動(dòng)化測試現(xiàn)狀
Trip.com App 在日常開發(fā)迭代過程中, UI 自動(dòng)化測試的應(yīng)用場景有很多,例如冒煙測試、探索測試,以及基于 Web Service 的 UI 自動(dòng)化測試平臺(tái)。接下來,向大家分別介紹不同測試在 CI/CD 中扮演的角色和作用。
應(yīng)用場景
冒煙測試
基本概況
- 在程序設(shè)計(jì)和軟件測試領(lǐng)域 , 冒煙測試 (也包括信心測試 、健全性測試、 [1] 構(gòu)建驗(yàn)證測試 ( BVT ) [2] [3]、構(gòu)建驗(yàn)收測試 )是指初步地進(jìn)行測試,并以此展示一些簡單但足以影響發(fā)布軟件版本的這一高級別的錯(cuò)誤。—— Wikipedia
在 Trip.com 實(shí)際應(yīng)用場景中,冒煙測試所擔(dān)任的角色主要是 Merge Request 卡點(diǎn)檢測,其主要作用是對 Trip.com App 的集成編譯以及運(yùn)行時(shí)閃退的預(yù)先校驗(yàn)。比如,對于多模塊并行開發(fā)的情況下,不同團(tuán)隊(duì)的某些改動(dòng)就會(huì)造成符號(hào)名找不到的問題,而冒煙測試就可以預(yù)先對此進(jìn)行卡點(diǎn),避免集成打包失敗降低試錯(cuò)成本和時(shí)間成本。
而對于 Trip.com iOS 的冒煙測試具體實(shí)踐,就是在主項(xiàng)目中創(chuàng)建 UITest Target 編寫簡單的 UI 視圖校驗(yàn)程序,并接入 GitLab Runner Pipeline,利用 xcodebuild 工具鏈對編譯過程和運(yùn)行時(shí)健壯性進(jìn)行初步校驗(yàn),以保證合入主分支的代碼,不會(huì)使 App 出現(xiàn)明顯的重大閃退等問題。
數(shù)據(jù)體現(xiàn)
冒煙測試在 Trip.com 快速迭代開發(fā)的過程中,作為 Merge Request 的卡點(diǎn)任務(wù),利用多臺(tái) GitLab Runner 實(shí)現(xiàn)并發(fā)執(zhí)行六個(gè)冒煙測試任務(wù),大大縮減了卡點(diǎn)校驗(yàn)的時(shí)間,單個(gè)冒煙測試時(shí)間控制在 6min 之內(nèi),不僅達(dá)到了驗(yàn)證集成包的編譯構(gòu)建和健壯性的目的,還大大節(jié)省了測試驗(yàn)證的時(shí)間成本。
探索測試
基本概況
探索性測試(Exploratory Testing)是軟件測試方法的一種,它的特點(diǎn)為在進(jìn)行測試時(shí),同時(shí)探索開發(fā)更多不同型態(tài)的測試方式,以便改善測試流程。—— Wikipedia
探索測試在 Trip.com App 實(shí)際應(yīng)用場景中,主要擔(dān)任的角色是 App 頁面隨機(jī)測試,主要用于驗(yàn)證集成打包 App 的質(zhì)量,隨機(jī)點(diǎn)擊頁面,并收集和統(tǒng)計(jì) Page View 以及 Crash 數(shù)據(jù),最終整理成報(bào)告發(fā)給相關(guān)開發(fā)同學(xué)。
Trip.com iOS 探索測試是基于 Google eDistantObject 和 EarlGrey 開源項(xiàng)目開發(fā)的白盒/灰盒 UI 測試框架。區(qū)別于 XCUITest 編寫 Test Case 并且必須結(jié)合 Accessibility 的測試方式,白盒/灰盒的探索測試框架,則是利用 Test App 和 Host App 進(jìn)程間通信,使 Test App 驅(qū)動(dòng) Host App 進(jìn)行 UI 自動(dòng)化測試,而 App 的元素審查、用戶交互以及數(shù)據(jù)收集則都是在 Host App 進(jìn)程中完成。 沒有了 Accessibility 的限制,白盒/灰盒的探索測試元素審查更全面,穩(wěn)定性更高,測試數(shù)據(jù)也相應(yīng)更全面。
數(shù)據(jù)體現(xiàn)
Trip.com 探索測試是用于驗(yàn)證 App 集成包穩(wěn)定性的日常 Jenkins 任務(wù),收集全部觸達(dá)頁面,可有效預(yù)先發(fā)現(xiàn) Crash 問題,并發(fā)送測試結(jié)果的報(bào)告郵件給研發(fā)組。iOS 的探索測試在并發(fā)數(shù)為 5 的情況下,2 小時(shí)測試有效觸達(dá)非重復(fù)頁面可達(dá) 180 個(gè),場景涉及首頁 Feed 流、玩樂旅拍、訂單頁面等場景。探索測試收集的 Crash 問題,會(huì)收集崩潰調(diào)用棧整理成表格,分配給相關(guān)研發(fā)同學(xué),推動(dòng)產(chǎn)線修改相關(guān)問題代碼。
UI 自動(dòng)化測試平臺(tái)
基本概況
Trip.com App UI 自動(dòng)化測試平臺(tái),是由 IBU 公共測試團(tuán)隊(duì)和 IBU 公共無線共同設(shè)計(jì)搭建的可視化、數(shù)據(jù)統(tǒng)一管理的質(zhì)量保證平臺(tái)。在 App 快速迭代的開發(fā)過程中,為提高測試效率,利用多臺(tái)機(jī)器,搭建 Jenkins 集群,實(shí)現(xiàn)用例并發(fā)執(zhí)行 Case,進(jìn)行 App 回歸測試,減少人力測試成本,并將測試問題報(bào)告反饋給相關(guān)開發(fā)同學(xué),推動(dòng)開發(fā)同學(xué)完善功能,從而,保證 App 上線前的質(zhì)量。而選用的測試框架主要是 Macaca,并且將逐步向 Appium 遷移改造。
數(shù)據(jù)體現(xiàn)
UI 自動(dòng)化平臺(tái)目前處于開發(fā)的一階段,日常回歸測試中,對于復(fù)雜業(yè)務(wù)場景的測試,機(jī)器性能穩(wěn)定且并發(fā)數(shù)目 6 的情況下,測試總耗時(shí)可控制在 40 分鐘,測試總用例數(shù)可達(dá) 209 個(gè),Step總數(shù) 3077 步,F(xiàn)eature 通過率達(dá) 97.14% ,Case 通過率達(dá) 98.56%。
以上不同的自動(dòng)化測試應(yīng)用實(shí)踐,接入不同的 CI/CD 流程中,都為 Trip.com App 快速開發(fā)迭代過程中提供了質(zhì)量保證。
總結(jié)
對于 iOS 平臺(tái)下的 UI 自動(dòng)化測試技術(shù),Apple 官方提供的兩個(gè)核心技術(shù)是 XCUITest 和 Accessibility。而為了能夠增強(qiáng)復(fù)用性,更利于分布式進(jìn)行自動(dòng)化測試,不同廠商又在此基礎(chǔ)上設(shè)計(jì)實(shí)現(xiàn)了基于 Web Service 的自動(dòng)化測試平臺(tái),優(yōu)點(diǎn)是具有易部署、跨平臺(tái)等特性,可以更大程度上利用分布式增強(qiáng)并發(fā)性,提高測試效率,減少人力測試成本。
當(dāng)然,市面上 UI 自動(dòng)化框架還有很多,例如 STF 和 Airtest,這類框架底層驅(qū)動(dòng)利用圖形圖像識(shí)別進(jìn)行 App 元素的定位。而對于目前 Trip.com iOS 的自動(dòng)化測試應(yīng)用實(shí)踐,則更多是基于 XCUITest 框架實(shí)現(xiàn)的,所以本文暫不討論此類測試框架。但不論何種驅(qū)動(dòng)進(jìn)行 App 的自動(dòng)化測試,整體的架構(gòu)設(shè)計(jì)都會(huì)以文中介紹的 Web Service 進(jìn)行設(shè)計(jì),以達(dá)到跨平臺(tái)、易集成、高復(fù)用等目的。
本文轉(zhuǎn)載自微信公眾號(hào)「Swift社區(qū)」