---
title: QA 自動化不是寫更多測試，是建閉環 — 從票務到只重跑失敗
description: 自動化測試的天花板不是「寫得多」，是「跑完之後」。這篇拆一條跑真交易所的四層閉環：票務 → BDD 場景單一真相源 → Robot 執行 → 每日只重跑失敗 → 回報儀表板，附 12,293 個 BDD 場景、1,620 個 Robot 測試、WHAT-vs-HOW 分離、Android 冷開機三訊號就緒閘門等真實做法。
category: automation
tags: [test-automation, ci-cd, robot-framework, bdd, flaky-tests]
date: 2026-07-27
faq:
  - q: 為什麼「寫更多自動化測試」不是重點？
    a: 因為自動化的價值不在測試數量，在「跑完之後有沒有形成閉環」。散在各 repo、結果不透明、fail 要人工重跑、季度成效講不出數字——寫再多測試都是黑箱。真正該建的是：票務驅動產測試 → 單一真相源管場景 → 自動執行 → 只重跑失敗 → 結果回流儀表板，讓整條路可量化、可追溯、可自我修復。
  - q: WHAT-vs-HOW 分離是什麼、為什麼重要？
    a: 把「測什麼」（測試意圖、預期、user level 矩陣，用業務語言）跟「怎麼測」（Robot / 自動化程式碼）拆成兩層，只靠測試案例名字對映。好處：QA/PM 不用讀自動化 code 就能 review 意圖，自動化實作可以獨立演進不動到 spec。這也讓 12k 級的案例庫能從無版控的 Excel 搬進 git，變成可 diff、可 MR review。
  - q: 夜跑的 App 測試很 flaky 怎麼辦？
    a: 多數 flaky 來自「還沒真的 ready 就開始測」。以 Android 冷開機為例，用三訊號就緒閘門取代盲目 sleep：先等 sys.boot_completed、再等 settings service 有回應、最後等輸入法 IME 綁定完成，三個都過才開跑。搭配殺乾淨舊 emulator/session、調冷開參數防 APK 累積爆磁碟，就能把 flaky 夜跑變成確定性。
  - q: 自動化成效怎麼量化又不失真？
    a: 兩個原則。一、兩來源對帳建立信任：自動化數量從執行結果 Sheet 讀，再用季末 commit 快照數（數 Robot 的 Test Cases、JS 的 test()）交叉驗，對得起來才報。二、誠實計量：AI 輔助 = 按規格手刻加速加人把關，絕不能寫成「全自動、不耗人力」。管理層最在意失真，浮誇一次就賠掉所有數字的可信度。
---

# QA 自動化不是寫更多測試，是建閉環

很多團隊衡量自動化成熟度的方式是「我們寫了幾個測試」。這個數字**幾乎沒有意義**。

真正決定價值的是**跑完之後發生什麼**：測試結果透明嗎？失敗會不會自己重跑？季末講得出成效數字嗎？票務進來會不會自動變成測試？如果這些都是「人工」或「不知道」，那你寫再多測試，都只是一堆黑箱。

自動化的天花板不在「寫得多」，在**「有沒有形成閉環」**。這篇是一條跑真交易所（帳戶／出入金／訂單簿／餘額，錯了會出事）的完整閉環怎麼組起來的。

## 全景：一條四層閉環

```mermaid
flowchart LR
    T[票務系統<br>AC + MR] --> E[AI 引擎層<br>codegen]
    E --> B[BDD 場景庫<br>單一真相源<br>12,293 場景]
    B --> R[Robot 執行層<br>1,620 測試]
    R --> J[CI 平行跑<br>只重跑失敗]
    J --> S[(結果 Sheet)]
    S --> D[儀表板<br>自動化指標]
    D -.閘門觸發.-> J

    style E fill:#f59e0b,color:#fff
    style B fill:#06b6d4,color:#fff
    style R fill:#10b981,color:#fff
    style D fill:#7c3aed,color:#fff
```

四層各司其職：**AI 引擎**產碼、**BDD 場景庫**是唯一真相源、**Robot 執行層**跑真環境、**儀表板**收指標並反過來觸發重跑。重點不是任何單層多聰明，是**四層串成一條會自己轉的環**。

---

## 一、單一真相源：WHAT vs HOW 分離

閉環的地基，是把測試案例從**無版控的 Excel**（動輒幾 MB、沒人敢動）搬進 **git**。搬進來之後做一件關鍵的事——**WHAT 跟 HOW 分兩層**：

```mermaid
flowchart TB
    subgraph WHAT[場景庫 · 測什麼]
        W1["Given/When/Then<br>測試意圖 + 預期"]
        W2["user level 矩陣"]
    end
    subgraph HOW[Robot · 怎麼測]
        H1["自動化實作碼"]
    end
    WHAT -->|只靠案例名字對映| HOW

    style WHAT fill:#06b6d4,color:#fff
    style HOW fill:#10b981,color:#fff
```

- **場景庫**存「測什麼」：意圖、預期、user level 矩陣，用**業務語言**寫成 Given/When/Then。QA/PM 看得懂、能 review。
- **Robot 層**存「怎麼測」：自動化程式碼。
- 兩層**只靠測試案例的名字對映**，各自獨立演進。

這樣 QA/PM 不用讀一行自動化 code 就能 review 測試意圖，而自動化實作可以重構、可以換 driver，完全不動到 spec。這 12,293 個場景（App + Web 合計、近百個模組）就是這樣變成可 diff、可 MR review、可 branch-per-ticket 的。

**level 參數化**是另一個放大器：一個「人類場景」用 level 矩陣展開成 N 個 Robot 測試（例如同一個提領流程，對 L0/L1/L2/未綁銀行各有不同預期）。這就是為什麼「12k 場景」對映到的自動化面比 12k 大得多。

---

## 二、票務驅動：票進來，自動變成測試骨架

閉環的入口是票務。一張功能票有驗收條件（AC）和對應的 MR，這些就是產測試的原料：

`票（AC + MR）` → `AI 產 Python 測試骨架 + harness` → `寫進測試分支` → `merge`

單元測試要行級細節、整合測試只要邊界，所以餵 context 時**主票給完整 diff、聚合子票只給檔名**（省約 95% token）。產出的不是「能跑就好」的碼，而是**符合團隊慣例**的碼——因為慣例本身被寫成了機器可檢查的規範（見下一節）。

---

## 三、data-driven 預期：別把「會過期的真相」寫死

跑真交易所最容易犯的錯，是把費率、提領上下限、上架幣種**寫死在測試裡**。這些東西**天天在變**，寫死的測試明天就是紅的（而且是假紅）。

正解：**對平台自己的真相源驗證**。每次跑之前先抓一份即時的交易所 metadata 快照（幣別確認數、提領上下限、維護狀態、下市對、VIP 費率……），在 runtime 導出預期值。

> 測試斷言的不是「手續費應該是 0.1%」，而是「手續費應該等於平台此刻宣告的值」。真相源變了，測試自動跟上，不用改一行 code。

---

## 四、把 flaky 夜跑變確定性：三訊號就緒閘門

夜跑 App 測試最惱人的是 flaky——早上來看一片紅，重跑又全綠。多數 flaky 的根因是**「還沒真的 ready 就開始測」**。

以 Android 冷開機為例，別用盲目的 `sleep 30`，改用**三訊號就緒閘門**：

```mermaid
flowchart LR
    C[冷開 emulator] --> S1{sys.boot_completed?}
    S1 -->|是| S2{settings service<br>有回應?}
    S2 -->|是| S3{IME 輸入法<br>綁定完成?}
    S3 -->|是| GO[開始測試 ✅]
    S1 -->|否| S1
    S2 -->|否| S2
    S3 -->|否| S3

    style GO fill:#10b981,color:#fff
```

三個訊號都過才開跑。搭配：殺乾淨舊的 emulator / session（別讓上一輪殘留污染）、調冷開參數（不載入 snapshot、指定 GPU 模式、加大 partition 防 APK 累積爆磁碟）。這樣就能把「flaky 夜跑」變成「確定性夜跑」。

---

## 五、閉環收尾：只重跑失敗 + 自動回流

最後一段，也是「閉環」真正閉起來的地方：

```mermaid
flowchart LR
    F[完整跑一輪] --> S[(寫結果 Sheet)]
    S --> G{通過率 > 85%?}
    G -->|是, 進閘門| RR[CI 只重跑<br>失敗的]
    RR --> M[rebot 合併結果]
    M --> S2[(回填 Sheet)]
    S2 --> D[儀表板消費]
    D --> N[Slack 通知]

    style G fill:#f59e0b,color:#fff
    style RR fill:#10b981,color:#fff
    style D fill:#7c3aed,color:#fff
```

- 完整跑一輪，結果寫進 Sheet。
- 儀表板讀失敗標記，**過通過率閘門**（例如 >85%）才觸發重跑——用 `<tag>` 對 Sheet，**不是用 test name**（名字會改、tag 穩定）。
- CI **只重跑失敗的**、再用 `rebot` 合併，不重跑全套。
- 結果回填 Sheet → 儀表板消費 → Slack 通知。

按 user level 分組平行跑、只重跑失敗、合併——這幾步讓「一個 flaky 失敗」不用賠掉整輪的時間。

---

## 別忘了：慣例即程式碼 + 誠實計量

**慣例即程式碼**：AI codegen 需要一個「機器可檢查的目標契約」。把團隊慣例（keyword 命名、xpath 大小寫、「≥2 個斷言要用 continue-on-failure」等）寫成幾百行規範，再配一個 linter skill 對分支 diff 報 🔴🟡🟢——這就是 AI 產碼的**驗收閘門**。沒有這層，AI 產的碼會慢慢腐化成各寫各的。

**誠實計量**（管理層最在意的一條）：

- 自動化數量**兩來源對帳**——從執行結果 Sheet 讀，再用季末 commit 快照數（數 Robot 的 `*** Test Cases ***`、JS 的 `test()`）交叉驗，對得上才報。
- AI 測試輔助 = **按規格手刻加速 + 人把關**，**絕不寫成「全自動、不耗人力」**。取材分界也要明確：哪些算「QA 用 AI」、哪些屬另一個專案，不能混報。

> 浮誇一次，就賠掉整個儀表板的公信力。閉環的最後一塊，是讓數字誠實到主管敢拿去對 keynote。

---

## 一句話

> 自動化的價值不在「寫了幾個測試」，在「跑完之後這條路會不會自己轉」——從票務進來、產碼、跑真環境、只重跑失敗、回流儀表板。**你建的不是測試，是一條會自我修復的閉環。**
