MetricKit 的診斷載荷不會配合提交節奏送達。即使今天只改了解析器的一行程式碼,真正的當機或卡頓報告也可能要幾天後才會揭露欄位遺失。更穩妥的做法,是將已取得的載荷去識別化、正規化並保存為固定樣本,讓雲端 Mac 在每次提交時都重播同一批輸入。如此驗證的是診斷處理鏈路本身,而不是等待下一次偶發事件。
先劃清測試邊界
固定樣本適合涵蓋四層邏輯:原始 JSON 能否讀取、系統欄位能否映射到內部模型、敏感內容是否已清除,以及異常輸入能否降級處理。它無法證明系統一定會產生載荷,也不能取代裝置端的回呼驗證。
建議將接收程式碼與業務處理拆開。接收層只負責取得 jsonRepresentation()、寫入受保護目錄並排入上傳佇列;解析層接收 Data,輸出不依賴 MetricKit 型別的內部結構。單元測試只呼叫後者,避免測試目標必須偽造系統物件。
樣本的價值不在於模擬一次成功解析,而是固定輸入契約,讓每次修改解析器時都能回答:「哪些欄位改變了,哪些資訊遭到捨棄?」
建立可納入版本控制的正規化樣本
原始載荷可能包含套件識別碼、裝置資訊、時間、呼叫堆疊符號與本機路徑。不要直接提交。應先在受限環境中保留原始資料,再產生可放入儲存庫的正規化副本:將時間改為固定值、識別碼改為測試值、路徑替換為 $APP、$HOME,並保留呼叫堆疊位址的格式,但不保留真實位址。
可以在內部格式中加入 schema,但不要改寫原始 MetricKit 版本。目錄依診斷類型組織:
Tests/Fixtures/MetricKit/
├── crash/basic.json
├── crash/missing-stack.json
├── hang/main-thread.json
├── disk-write/threshold.json
└── malformed/truncated.json
每個樣本只表達一項條件。若同一個檔案同時包含當機、卡頓與磁碟異常,測試失敗後將很難定位原因。樣本名稱應描述輸入,而不是預期結果;預期值則放在測試程式碼中,審查時更容易發現斷言是否被順手修改。
執行測試前先設置結構門禁
在編譯測試前先用 jq 進行低成本檢查,可以迅速攔截無效 JSON、遺漏版本與尚未去識別化的路徑。以下的 diagnostics 是團隊自行定義的正規化陣列,並非假設系統原始載荷具有相同結構。
set -euo pipefail
root="Tests/Fixtures/MetricKit"
find "$root" -name '*.json' -print0 |
while IFS= read -r -d '' file; do
jq -e '
type == "object" and
.schema == 1 and
(.diagnostics | type == "array") and
all(.diagnostics[];
(.kind | type == "string") and
(.timestamp | type == "string") and
(.stackID | type == "string")
)
' "$file" >/dev/null
if grep -E '/Users/|/private/var/|[A-F0-9]{16,}' "$file"; then
echo "fixture contains unnormalized data: $file" >&2
exit 1
fi
done
結構門禁不應規定所有系統欄位,否則新增選用欄位時會造成無意義的失敗。只需檢查內部處理真正依賴的鍵,並讓解碼器忽略未知欄位。
用正向與反向樣本涵蓋解析契約
至少準備一組正常輸入與三組失敗輸入。測試重點不只是「沒有拋出錯誤」,而是輸出是否仍可供彙整、告警與問題排查使用。
| 樣本 | 預期行為 | 不應發生 |
|---|---|---|
| 完整當機資料 | 輸出類型、時間與堆疊識別碼 | 保存原始本機路徑 |
| 空診斷陣列 | 傳回空結果 | 視為解碼失敗 |
| 缺少呼叫堆疊 | 標記為不完整 | 將偽造的空堆疊視為正常資料 |
| 截斷 JSON | 傳回可分類的錯誤 | 程序直接結束 |
| 未知類型 | 記錄未知列舉值 | 捨棄整批載荷 |
斷言內部模型,而非整段 JSON
整段快照很容易受到欄位順序與無關中繼資料變動的干擾。應優先斷言診斷數量、類型、穩定識別碼與去識別化結果;只有在正規化輸出需要跨系統交換時,才加入格式化 JSON 快照。錯誤也應定義為可比較的列舉值,例如 invalidJSON、missingRequiredField、unsupportedDiagnostic,不要只比較容易變動的自然語言訊息。
整合至雲端 Mac CI
在 VMRunner 的雲端 Mac 上,應將 fixture 檢查安排在單元測試之前,並確保非互動式工作使用固定的工作目錄。一套可行的執行順序是:簽出程式碼、執行結構門禁、執行解析器單元測試、產生測試結果,最後檢查工作區是否出現尚未提交的樣本變更。
樣本變更必須單獨審查。新增系統欄位時,先確認解析器是否需要使用;若需要,應升級內部 schema,並同時提交遷移測試;若不需要,則維持寬鬆解碼。不要讓指令碼在 CI 中自動覆寫基準檔案,否則真正的欄位遺失可能會被新的錯誤結果「核准」。
合併前檢查項目
- 原始載荷已在儲存庫外完成去識別化。
- 每個樣本只涵蓋一項診斷條件。
- 正常、空值、缺少欄位、截斷與未知類型均有測試。
- 未知的選用欄位不會導致整批處理失敗。
- 本機路徑、長識別碼與使用者內容無法通過門禁。
- 解析失敗會傳回穩定的錯誤類別。
- fixture 變更與解析器變更由同一次審查確認。
完成這些約束後,MetricKit 診斷處理就會從「收到資料後再嘗試」轉變為一般且可重複執行的工程測試。系統載荷仍需在裝置端驗證,但解析、去識別化與相容性不再依賴偶然送達的報告。
常見問題
MetricKit 固定樣本能完全取代實機驗證嗎?
不能。固定樣本適合驗證解析、去識別化、映射及異常降級邏輯;系統是否正常產生並回傳診斷載荷,仍須透過受控裝置測試與正式環境觀測確認。
應該直接把原始 MetricKit JSON 放進版本庫嗎?
不建議。可將去識別化的原始資料存放在限制存取的位置,版本庫只保留移除使用者識別碼、本機路徑與敏感內容後的正規化樣本。
出現未知的新欄位時,CI 應立即失敗嗎?
通常不需要。解碼器應容許新增的選用欄位,但若內部契約要求的診斷類型、時間或呼叫堆疊識別碼缺失,就必須讓測試失敗。
將下一次建置放到獨享雲端 Mac 上執行
選擇機型、節點與計費週期。下單前會完整列出設定與美元金額,實際可用狀態以控制台即時回傳為準。