在雲端 Mac 上用 simctl 建立 iOS 生物辨識回歸測試

Security ·約 6 分鐘閱讀

在雲端 Mac 上用 simctl 建立 iOS 生物辨識回歸測試

登入頁剛完成一次重構,本機也驗證了密碼回退流程,卻沒有人注意到「尚未註冊生物辨識」的分支已經無法繼續。直到測試環境重複使用一臺舊模擬器,流程才偶發卡住。這類問題不在演算法,而是測試沒有控制驗證狀態。雲端 Mac 適合將模擬器狀態、驗證事件與清理步驟固化成流水線,讓每次提交都覆蓋同一組分支。

先界定自動化範圍

simctl biometric 可以模擬已註冊、未註冊、比對成功與比對失敗事件,適合檢查應用程式收到結果後的介面與狀態轉換。它無法驗證感測器、實際註冊流程,也不能證明裝置層級的安全性。測試目標應限定為四件事:

情境 注入狀態 應用程式預期行為
驗證成功 enroll + match 進入受保護頁面
使用者拒絕 enroll + nonmatch 保留目前頁面並允許重試
尚未註冊 unenroll 顯示可執行的替代路徑
功能不可用 測試替身回傳錯誤 不重複彈出視窗,也不遺失使用者輸入

模擬器測試證明的是「應用程式能正確處理系統結果」,而不是「生物特徵本身可靠」。

真實裝置驗收仍應保留,但不必把每個業務分支都壓在人工操作上。

將系統驗證封裝成可替換的邊界

如果檢視控制器直接建立驗證內容,單元測試就只能等待系統視窗。更穩定的做法是定義一個小型協定,讓正式環境的實作呼叫系統框架,測試實作則回傳確定的結果。

import LocalAuthentication

protocol BiometricAuthenticating {
    func authenticate(reason: String) async throws -> Bool
}

struct SystemBiometricAuthenticator: BiometricAuthenticating {
    func authenticate(reason: String) async throws -> Bool {
        let context = LAContext()
        var error: NSError?
        guard context.canEvaluatePolicy(
            .deviceOwnerAuthenticationWithBiometrics,
            error: &error
        ) else {
            throw error ?? LAError(.biometryNotAvailable)
        }
        return try await context.evaluatePolicy(
            .deviceOwnerAuthenticationWithBiometrics,
            localizedReason: reason
        )
    }
}

業務層只接收 BiometricAuthenticating。單元測試負責完整涵蓋錯誤對應,介面測試則保留少量端對端案例,確認系統面板出現後,成功、失敗與回退按鈕確實連到正確頁面。如此一來,即使系統提示文字隨版本變更,核心判斷也不會依賴脆弱的全文比對。

固定模擬器並驅動驗證狀態

先查看目前工具支援的參數,避免直接複製另一套執行環境中的命令格式:

xcrun simctl help biometric
xcrun simctl list devices available

流水線不應使用模糊的 booted 選擇器。當平行任務同時啟動裝置時,它可能會選中錯誤的執行個體。每個任務應建立或取得唯一的 UDID,並在所有命令中持續使用:

set -euo pipefail

UDID="${SIMULATOR_UDID:?missing simulator udid}"

xcrun simctl boot "$UDID" 2>/dev/null || true
xcrun simctl bootstatus "$UDID" -b
xcrun simctl biometric "$UDID" unenroll
xcrun simctl biometric "$UDID" enroll

啟動測試後,必須等到驗證面板真正就緒再傳送事件。固定暫停兩秒很容易在負載變化時失效。可以讓測試建置版本在觸發驗證前輸出自訂標記,例如 AUTH_PROMPT_READY,外層控制器在設有逾時的日誌串流中觀察到標記後,再執行:

xcrun simctl biometric "$UDID" match face
xcrun simctl biometric "$UDID" nonmatch face

不同執行環境接受的生物辨識類型參數可能有所差異,因此最終命令應以本機 help biometric 的輸出為準,並在環境預檢階段直接失敗,而不是等到測試執行途中才發現不相容。

讓測試案例彼此獨立

生物辨識註冊狀態屬於模擬器,而不屬於單一測試方法。前一個案例留下的 enroll 會污染下一個「未註冊」測試。建議為每個情境明確設定前置狀態,並在測試結束時復原:

cleanup() {
  xcrun simctl biometric "$UDID" unenroll 2>/dev/null || true
  xcrun simctl shutdown "$UDID" 2>/dev/null || true
}
trap cleanup EXIT

不要共用同一個裝置集

在同一臺 LemonVM 雲端 Mac 上平行執行多個測試分片時,應為每個任務設定獨立的 --set 目錄,或預先分配不同的 UDID。裝置集、DerivedData 與結果套件都應依任務識別碼分別建立目錄,避免某個任務刪除另一個任務的裝置。

不要斷言系統提示文字

系統對話框會受到系統版本、語言與裝置能力影響。介面測試應尋找系統面板、應用程式自有按鈕及最終業務狀態,不要逐字斷言系統提示。錯誤類型的精確對應應在使用協定替身的單元測試中完成。

建立失敗取證與准入清單

測試失敗時,至少應保存測試結果套件、應用程式日誌、目標 UDID、系統版本、模擬器型號,以及案例開始前的註冊狀態。只截取一張失敗畫面,通常無法判斷是事件傳送過早、選錯裝置,還是應用程式沒有處理回呼。

提交前可依照以下清單驗收:

這套結構的價值不在於多執行幾條命令,而是把「驗證狀態」從不可見的前提轉換成測試輸入。只要輸入、裝置與時序都能被記錄,生物辨識回歸測試就能從偶發的人工檢查,轉變為可重複執行的工程步驟。

常見問題

simctl biometric 可以取代實體裝置的生物辨識測試嗎?

不可以。它適合驗證應用程式的狀態分支、提示流程與替代入口,但不能驗證感測器品質或真實註冊過程,發布前仍需保留實體裝置驗收。

為什麼測試偶爾收不到 match 或 nonmatch 事件?

常見原因是系統認證面板尚未出現就傳送事件,或多個工作共用同一模擬器。應等待可觀測的就緒標記,並為每個工作分配獨立 UDID。

獨享物理節點

依任務週期選擇 LemonVM 雲端 Mac

Lemon M4 與 Lemon M4 Pro 覆蓋新加坡、東京、首爾、香港及美國西部,支援日租、週租、月租與季租。

立即租用雲端 Mac