App Debug Acceptance 是編譯進 Debug App 的驗收入口。Agent 在獨立 Swift 檔案中準備場景、呼叫正式程式並寫斷言;App 完成初始化後,依啟動參數執行指定 case,將結果寫入同一輪 run ID 的 Log。

歷史難題:已有自動化能力,Agent 仍逐步操作 UI

appDebugCode 是我在 2023 年留下的掛點,用來在 App 初始化完成後快速重跑指定 function,驗證修改。當時 SwiftUI Preview 在我的專案裡不夠好用,部分功能也依賴 App 完成初始化,因此需要一個能在完整 App 環境中直接執行程式的位置。

後來我也整理過供 Agent 操作 App 的 Automation,但 Agent 仍常採用「截圖 → 判斷畫面 → 傳送遙控按鍵 → 再截圖」的流程。每輪驗收都要重新導航、準備設定,並從畫面確認操作進度;修復後還要重走一次。播放器 seek 的驗收也顯示,Agent 已經知道怎麼執行 seek。

這次改造把 Agent 的驗收工作單位固定為獨立 Swift case,並寫入 Skill 的執行流程:由程式準備資料與設定、呼叫正式方法、等待完成訊號並作斷言。修復後可以選擇同一個 case、帶入相同輸入重跑,再以新的 run ID 核對結果。原有掛點得以保留,個別任務則不必再共同修改 appDebugCode。

改善了什麼

驗收環節 以前:逐步截圖與遙控 現在:Swift case
準備場景 透過 UI 依序切換設定、選擇來源、搜尋與進入影片;每輪重新導航到目標狀態。 由 case 寫入本次資料與設定,帶入指定輸入,再呼叫正式搜尋或播放流程。
執行動作 每一步都經過截圖、判斷畫面和焦點、傳送按鍵,再查看下一張截圖。 在同一段 Swift 程式中串接正式方法呼叫與非同步等待,動作之間不需要逐步交回 Agent 看圖決定。
判定結果 從畫面確認是否進到下一步;精確的播放器位置或內部狀態還要另外查證。 直接讀取實際狀態作斷言,例如 seek 後的位置、暫停狀態與播放時間是否前進,並記錄檢查名稱和結果。
修復後重跑 重新操作同一串選單與按鍵,再確認測試設定和畫面位置。 沿用同一個 case 與輸入,以新的 run ID 重跑,對照每項檢查。已編譯的 case 可直接重新啟動;改過 Swift 程式則重新建置與安裝。

以目前的 HTTPPlayback case 為例,驗證「暫停時 seek」會執行以下檢查:

  1. 經正式 PlayerHelper 開片並保持暫停,等待播放器可 seek。
  2. 透過 App 的 HTTP 播放介面 seek 到 7.25 秒,斷言回傳狀態仍為 paused,且位置誤差小於 0.5 秒。
  3. 讀取實際掛載的 AVPlayer 時間,等待 500 毫秒後再次讀取,斷言時間變化小於 0.1 秒,確認暫停狀態確實保留。

這段測試一次由 case 執行,失敗時可從檢查名稱區分「位置不對」與「暫停沒有保留」。修復後直接重跑相同條件;焦點、字幕和排版等畫面問題,再以實際畫面驗收。

1. 執行位置與分工

入口放在 App 原有初始化流程之後:

#if DEBUG
await appDebugCode()
#endif

執行順序如下:

flowchart LR
    A["App 初始化"] --> B["appDebugCode"]
    B --> C["依 case ID 分派"]
    C --> D["case.run(runID:)"]
    D --> E["正式流程與斷言"]

appDebugCode 將啟動參數交給 StudyTVAcceptanceRuntime.runRequested,由它處理 case 查找與開始/完成事件。各 case 自己準備設定和測試資料,呼叫本次要驗證的正式功能。

Xcode 工具負責建置;主機端 helper 負責裝置確認、部署、啟動與取回證據。業務斷言留在 App 的 case 裡。

2. case 協定與分派