iT邦幫忙

2026 iThome 鐵人賽

DAY 7
1
Software Development

從脆弱腳本到可信任測試平台:自動化測試架構30天系列 第 7

Day 7|一個測試案例應該負責多少事情?論測試案例的粒度與獨立性

  • 分享至 

  • xImage
  •  

「如果你的測試案例失敗時,你無法在 3 秒內從案例名稱看懂是哪一個商業規則壞掉,那這個案例很可能包攬了太多不屬於它的責任。」

大家好,我是 Jane。

在 Day 6 我們聊到了從「單一腳本」演進到「測試框架」時需要抽離的 7 大核心要素。當我們有了基本的框架結構後,接下來每天要面對的硬功夫,就是寫出一條條「高品質、好維護」的測試案例。

剛開始寫自動化測試時,我們常會有一種直覺:

  • 「反正都要打開一次瀏覽器/建立一次 API Token,不如就把『註冊 > 登入 > 搜尋商品 > 加入購物車 > 結帳 > 退貨』全部寫在同一條測試裡吧!這樣跑起來多流暢啊!」

這種把整個 User Journey 塞進單一測試案例的作法,我們稱之為 「巨無霸案例(Monster Test / Long E2E)」

在 3 個案例時這樣寫看起來很省事,但到了 30 個案例時,這種「一條龍」寫法就會變成 CI 上的災難噩夢。今天這篇文章,我們就來聊聊:一個測試案例到底該負責多少事情?

一、 巨無霸案例(Monster Test)的 5 大致命痛點

為什麼資深 QA 都強烈建議避免過長的測試案例?因為它們帶來的維護成本極其高昂:

巨無霸案例範例:
test("使用者完成購物流程", async () => {
  // 步驟 1: 註冊帳號
  // 步驟 2: 登入
  // 步驟 3: 搜尋商品
  // 步驟 4: 加購物車
  // 步驟 5: 填寫地址
  // 步驟 6: 付款
  // 步驟 7: 檢查訂單紀錄
});

1. 失敗時定位困難(Hard to Locate)

當 CI 跑出失敗時,報告只會顯示:test "使用者完成購物流程" FAILED

你無法一眼看出到底是在「填寫地址」時彈出 Validation Error、還是在「付款」時 Timeout。你必須抓 Log、看截圖、甚至本地重跑才能知道壞在哪裡。

2. 前置步驟太多,重跑成本極高(High Re-run Cost)

如果測試在第 6 步「付款」失敗,為了排查問題,你每次修完腳本重跑時,都必須重新執行前 5 個步驟。這不但浪費 CI 執行時間,也增加了測試因為網路抖動而 Flaky 的機率。

3. 測試案例彼此依賴(Test Interdependency)

過長的案例往往伴隨著「狀態污染」。後面的驗證高度依賴前面步驟產生的資料(例如依賴上一步註冊成功生成的 User ID)。一旦前一步出錯,後面整條鏈結全部斷掉,產生一連串連鎖失敗(Cascading Failures)。

4. 測試意圖不明確(Vague Intention)

一個名稱叫 test_checkout_flow 的案例,到底是在驗證「折價券扣抵」、「運費計算」還是「信用卡格式檢查」?當一個案例驗證了 10 件不同的事,它就失去了作為「商業規格文件」的價值。

5. 多個驗證點被遮蔽(Assertion Masking)

在大多數測試框架中,第一個 assert 失敗後,程式碼就會中斷執行。如果你的巨無霸案例裡驗證了「商品名稱」、「小計金額」、「稅金」與「總金額」,一旦「商品名稱」斷言失敗,後面的金額驗證根本不會執行,你無法一次掌握所有壞掉的細節。

二、 最佳實踐:單一職責原則(Single Responsibility Principle)

一個好的自動化測試案例,應該遵守 AAA 模式(Arrange - Act - Assert),且符合 FIRST 原則

┌──────────────────────────────────────────────────────────┐
│                   Arrange (準備測試資料與環境)              │
├──────────────────────────────────────────────────────────┤
│                   Act     (執行單一被測動作)              │
├──────────────────────────────────────────────────────────┤
│                   Assert  (進行精準斷言驗證)              │
└──────────────────────────────────────────────────────────┘

1. 粒度控制:一次只驗證「一個商業規則」

測試案例的名稱應該要能直接反應商業期待:

  • test_shopping()
  • test_checkout_should_apply_discount_when_using_valid_coupon()
  • test_checkout_should_fail_when_credit_card_expired()

將巨無霸案例拆分成數個小而專一的案例後,即便其中一個失敗,其他案例依然能正常執行,為團隊提供精確的防線情報。

2. 利用 API 快速準備前置條件(Arrange via API)

「拆成小案例後,如果每個案例都要從登入、加購物車開始點,時間不會更慢嗎?」

這就是關鍵解法:只有被測試的主角需要走 UI / 操作,前置條件全部用 API 或 DB 快速預建!

  • 如果你要測試「付款頁面」,不要在 UI 上從搜尋商品一步步點到結帳頁。
  • 應該透過 API 直接建好包含商品的購物車,取得 Token 後,直接跳轉至付款頁面進行測試。

三、 第一線 QA 的折衷思維:Smoke Test vs. Fine-grained Test

有人會問:「Jane,難道我們完全不能寫任何 End-to-End 貫穿全流程的測試嗎?」

答案是:看測試的類型與層級。

在實務上,我們可以採取分層策略:

測試類型 案例粒度 數量比例 目的
Smoke / Happy Path E2E 貫穿主流程(全流程 1 條) 少 (5~10%) 部署後快速確認整個系統基本運作正常(如:能從頭到尾完成一次購買)。
功能與邏輯驗證 (Fine-grained) 專一、小粒度(各類邊界與情境) 多 (90%) 驗證各種組合、錯誤處理、權限限制與金額計算,前置步驟靠 API 準備。

四、 檢核你的測試案例:3 個 Self-Check 問題

寫完一個測試案例後,試著回答這 3 個問題,檢查粒度是否適中:

  1. 「如果這個案例亮紅燈,我是不是不需要看 Log,就能從名字猜出大概是哪個功能壞了?」
  2. 「這個案例如果失敗,會不會導致下一個原本正常的案例也跟著失敗?」
  3. 「如果 UI 流程的第 2 步介面改版,我有多少個案例會受到波及而需要修改?」

明日預告

討論完測試案例的責任與粒度後,接下來我們要面對的是測試程式碼本身的「維護性」。

很多 QA 會覺得「測試程式碼只要能跑就好,不用像產品程式碼那樣講究品質」。這種心態往往是測試程式碼演變成「垃圾場」的開端。

明天 Day 8,我們就來談談:《 Day 8|測試程式也需要良好的程式碼品質:別讓你的測試程式碼變成技術債 》


上一篇
Day 6|測試腳本與測試框架有什麼不同?從單一腳本到永續架構的演進之路
系列文
從脆弱腳本到可信任測試平台:自動化測試架構30天7
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言