一次普通的按鈕改名、圖示替換或約束調整,都可能讓 iOS 畫面失去可讀標籤、縮小點按區域,或導致文字在大字體下遭到截斷。人工巡查很難涵蓋每次提交。更可靠的做法,是在雲端 Mac 上固定模擬器與 App 狀態,使用 XCTest 執行無障礙稽核,再將失敗項目轉化為可重現的合併把關機制。
先定義把關範圍
不要一開始就遍歷整個產品。先選擇登入後首頁、核心編輯頁與提交確認頁等高頻路徑,且每個測試案例只驗證一種穩定狀態。動畫、隨機推薦、目前時間與網路回傳值都會改變元素樹,因此應在測試模式下停用,或注入固定資料。
第一輪建議檢查四類問題:
| 檢查項目 | 常見缺陷 | 把關處理 |
|---|---|---|
| 元素描述 | 圖示按鈕沒有可讀名稱 | 直接失敗 |
| 點按區域 | 控制項可見但難以點按 | 直接失敗 |
| 對比度 | 前景與背景難以區分 | 與設計核對後修正 |
| 文字版面 | 大字體下截斷或重疊 | 直接失敗 |
自動稽核負責找出機器能夠穩定判斷的問題,不能用來證明整套互動已經易於使用。閱讀順序、提示是否清楚,以及複雜手勢等項目,仍須保留人工檢查。
為測試建立確定的畫面
UI 測試最怕「相同入口,卻出現不同畫面」。App 應識別僅供測試使用的啟動參數,在啟動時清除暫存狀態、載入固定資料,並停用非必要動畫。這些參數只能改變測試環境,不得進入正式業務邏輯。
let app = XCUIApplication()
app.launchArguments = [
"-ui-testing",
"-reset-demo-state",
"-disable-animations"
]
app.launchEnvironment["TEST_LOCALE"] = "zh-Hans"
app.launch()
測試資料應在 App 行程內準備,不應讓 UI 測試依賴即時 API。若需要涵蓋載入中、無資料、錯誤與正常結果,請為每種狀態建立獨立參數。如此一來,發生失敗後只需複製命令即可重現,不必等待某個遠端條件再次出現。
固定元素定位方式
不要使用按鈕標題或座標定位關鍵控制項。標題會隨本地化而改變,座標則會受視窗與字體大小影響。請為可互動元素設定語意穩定的 accessibilityIdentifier:
checkoutButton.accessibilityIdentifier = "checkout.submit"
cartSummary.accessibilityIdentifier = "checkout.summary"
識別碼應描述元素職責,而不是視覺位置。footer.orangeButton 這類名稱會在版面改版後失去意義;checkout.submit 則能跨版面持續使用。
執行具針對性的 XCTest 稽核
當系統版本支援相關 API 時,可以針對已進入穩定狀態的畫面執行稽核。應先等待關鍵元素出現,再開始檢查,以免將載入期間的暫時版面誤判為缺陷。
func testCheckoutAccessibility() throws {
let app = XCUIApplication()
app.launchArguments = ["-ui-testing", "-reset-demo-state"]
app.launch()
let submit = app.buttons["checkout.submit"]
XCTAssertTrue(submit.waitForExistence(timeout: 10))
if #available(iOS 17.0, *) {
try app.performAccessibilityAudit(for: [
.sufficientElementDescription,
.hitRegion,
.contrast,
.textClipped
])
}
}
不要隨意建立全域忽略清單。如果確實需要暫時排除問題,應將範圍限制在明確的畫面、元素識別碼與問題類型,並在程式碼審查中註明移除條件。否則,忽略項目會逐漸演變成永久盲區。
在雲端 Mac 上固定執行條件
先檢視目前可用的模擬器裝置與執行環境,再由流水線傳入明確的 destination。不要假設每個節點都已經存在同名裝置。
xcrun simctl list devices available
xcrun simctl list runtimes
export SIM_DESTINATION='platform=iOS Simulator,name=iPhone 15,OS=17.5'
set -o pipefail
xcodebuild test \
-project ExampleApp.xcodeproj \
-scheme ExampleAppUITests \
-destination "$SIM_DESTINATION" \
-only-testing:ExampleAppUITests/AccessibilityTests \
-resultBundlePath "$PWD/TestResults/Accessibility.xcresult"
實際執行時,應將裝置名稱與系統版本設為流水線變數,並與節點已安裝的執行環境保持一致。執行前可建立全新的模擬器;若要重複使用既有裝置,則應先關閉 App 並清除測試狀態。平行任務不得共用同一個模擬器,否則語言、權限提示與上一個測試案例留下的狀態會互相污染。
雲端 Mac 的機型與節點選擇不會改變測試設計原則。需要新增執行環境時,請在控制台確認目前可選的配置,並記錄 Xcode 版本、執行環境版本、語言與 destination,確保失敗能在相同條件下重新執行。
分層執行並處理常見誤報
每次合併請求只執行核心畫面、預設語言與一種標準字體大小,將回饋時間控制在團隊可接受的範圍內。主分支再擴充至多語言、橫向與直向、深色外觀及動態字體。不要把所有組合塞進同一個測試方法;依畫面與狀態拆分後,失敗名稱本身就能指出影響範圍。
遇到不穩定的失敗時,請依下列順序檢查:
- 確認關鍵元素是否已完成載入,而非只是存在於元素樹中。
- 比對語言、地區、字體大小、方向與外觀設定。
- 檢查測試資料是否曾被上一次執行修改。
- 單獨重新執行失敗的方法,確認問題能否穩定重現。
- 保存測試結果套件、執行命令與環境欄位,再判斷是產品缺陷,還是測試隔離不足。
把關規則也應分級處理。缺少描述、無法點按與文字重疊適合直接阻止合併;尚未完成設計確認的對比度問題可以先記錄,但必須指定負責人與處理期限。最終目標不是取得一份永遠全綠的報告,而是讓每次失敗都能定位到具體的畫面、狀態、元素與環境條件。
常見問題
無障礙自動稽核能完全取代人工檢查嗎?
不能。自動稽核適合找出描述缺漏、點擊區域過小、對比不足與文字截斷,但閱讀順序、操作語意及實際體驗仍需人工驗證。
為什麼本機通過,到了雲端 Mac 卻失敗?
應先比對模擬器執行環境、語言、地區、動態字級、畫面方向及測試資料。把這些條件固定為啟動參數,才能降低環境差異。
完整無障礙稽核應該在什麼時候執行?
核心畫面的快速稽核適合每次合併請求執行;包含多語言與多種字級的完整矩陣,可安排在主要分支或排程工作中執行。
讓下一次建置在雲端 Mac 上執行。
比較三種 Apple Silicon 設定,從五個海外節點中選擇適合目前工作流程的區域。