iT邦幫忙

2026 iThome 鐵人賽

DAY 8
1
Software Development

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

Day 8|測試程式也需要良好的程式碼品質:別讓你的測試程式碼變成技術債

  • 分享至 

  • xImage
  •  

「當產品程式碼改動 1 行,你卻要跟著修改 10 檔測試程式碼時,問題往往不是出在產品改版,而是出在你的測試程式碼品質太差。」

大家好,我是 Jane。

在上集 Day 7 中,我們聊到了測試案例的粒度與獨立性,學會了如何把「巨無霸案例」拆解成小巧專一的測試。

今天我們要來面對一個許多 QA 甚至開發團隊常有的致命偏見

  • 「測試程式碼又不用上線給使用者看,能跑通、會亮綠燈就好了,幹嘛管什麼 Clean Code、設計模式?」

這種心態,往往就是自動化專案走向死亡的開始。

在實務中,測試程式碼的生命週期跟產品程式碼一樣長,甚至因為它要頻繁應對產品需求的變動,它對「可讀性」與「可維護性」的要求比產品程式碼還要高! 如果測試程式碼寫得亂七八糟、到處都是複製貼上,半年後當你需要維護它時,你會發現自己根本看不懂當時在寫什麼,最後只能無奈地將案例 skip 掉。

今天這篇文章,我們就來盤點 7 個最常出現在自動化測試中的「程式碼壞氣味(Bad Smells)」,以及第一線 QA 該如何重構它們!

一、 自動化測試最常出現的 7 大「程式碼壞氣味」

┌───────────────────────────────────────────────────────────────────┐
│                    測試程式碼常見壞氣味                            │
├───────────────────────────────────────────────────────────────────┤
│ 1. 神奇等待時間 (Magic Sleep)      5. 神奇數字與字串 (Magic Values) │
│ 2. 複製貼上牆 (Copy-Paste)         6. 隱藏副作用 (Side Effects)    │
│ 3. 測試邏輯洩漏 (Over-abstraction) 7. 幽靈斷言 (Weak/No Assertion) │
│ 4. 冗長混亂的命名 (Bad Naming)                                     │
└───────────────────────────────────────────────────────────────────┘

1. 神奇等待時間 (Magic Sleep / Fixed Sleep)

  • 壞氣味:程式碼裡隨處可見 Thread.sleep(5000)await page.waitForTimeout(3000)
  • 後果:網路快時浪費執行時間,網路慢時腳本依然跳 Timeout 失敗。這是導致 CI 時間拉長與 Flaky Test 的第一大元兇!
  • 重構作法完全摒棄固定等待! 改用條件式等待(Explicit Wait)或輪詢(Polling),如 waitForElementVisible()waitForResponse()

2. 複製貼上牆 (Copy-Paste / Duplicate Code)

  • 壞氣味:每一個檔都有 20 行一模一樣的「設定 Header、取得 Token、初始化 Driver」程式碼。
  • 後果:當 Token 的 Key 名稱改變時,你需要手動打開 30 個測試檔案逐一修改。漏改一個,CI 就跳紅燈。
  • 重構作法:抽離共用邏輯至 BeforeEach Hook、Fixture 或 Helper Utility,遵守 DRY 原則(Don't Repeat Yourself)。

3. 神奇數字與字串 (Magic Numbers & Strings)

  • 壞氣味await page.fill('#input-3', 'test_user_881923')expect(res.status).toBe(200)(但沒有解釋 881923 代表什麼特殊的權限帳號)。
  • 後果:接手的新人完全看不懂這些神秘字串與數字背後的商業含義。
  • 重構作法:使用具名常數(Constants)、Enum 或導出有意義的測試資料物件(例如 TestUsers.EXPIRED_VIP_USER)。

4. 過度抽象與邏輯洩漏 (Over-abstraction vs. Leakage)

  • 壞氣味
    • 過度抽象:為了追求簡潔,把 5 個斷言包進一個叫 checkEverything() 的黑盒子函式裡,失敗時根本不知道是哪裡出錯。
    • 邏輯洩漏:在 Test Case 裡寫滿了 page.locator('div > ul > li:nth-child(3) > button').click() 底層細節。
  • 重構作法:Test Case 層級只應該展現「測試意圖(Intent)」「商業斷言」;底層的操作細節(如何點擊、如何定位)應該封裝在 Page Object 或 API Client 層(分層設計)。

5. 冗長混亂的命名 (Bad Naming)

  • 壞氣味test1()checkLogin()testError()
  • 後果:測試失敗時,報告上的名字無法提供任何排查線索。
  • 重構作法:採用 Given-When-Then[Feature][Condition][ExpectedResult] 的清晰命名模式:
    • login_with_invalid_password_should_show_error_message()

6. 隱藏副作用 (Side Effects & State Pollution)

  • 壞氣味:測試案例執行完後,沒有清理建立的測試資料,或是修改了全域變數,導致下一個執行的測試案例被污染而失敗。
  • 重構作法:保持案例的純粹性(Purity),每個案例建立的資料應帶有唯一識別碼(如 uuid),並在 AfterEachAfterAll 做好資源釋放與清理。

7. 弱斷言或幽靈斷言 (Weak or Missing Assertions)

  • 壞氣味:只驗證 expect(response).isNotNull(),卻沒有驗證 Response 裡的資料內容是否正確;或者連一個 assert 都沒寫,以為「程式碼沒噴 Exception 就算 Pass」。
  • 重構作法:精準斷言!斷言必須命中商業邏輯的核心結果(Status Code、Body Key-Value、DB 欄位狀態變化)。

二、 讓測試程式碼變乾淨的 3 個心法

心法 1:測試程式碼也要做 Code Review (CR)

如果團隊裡 QA 寫的自動化程式碼從來不用經過 Dev 或其他 QA 的 Code Review,品質一定會失控。透過 CR,大家可以一起討論:

  • 「這個定位器是不是太脆弱了?」
  • 「這個邏輯是不是可以抽成共用 Helper?」
  • 「案例名稱有沒有表達清楚測試意圖?」

心法 2: readability > Cleverness(可讀性遠大於技巧性)

在產品程式碼中,我們可能會為了極致的效能而寫出一些複雜的演算法或設計模式;但在測試程式碼中,『可讀性』永遠是第一考量!
寫得直白、易懂、結構清晰,讓任何接手的人都能像讀「商業規格書」一樣閱讀你的測試程式碼,就是最高品質的體現。

心法 3:像重視產品一樣進行測試重構(Test Refactoring)

當你發現某個頁面的定位器改版、或是某個 API 格式變動時,不要只是「修補」那個壞掉的腳本。順手把重複的邏輯抽離、把舊的 waitForTimeout 換掉。漸進式的重構,能防止測試程式碼快速腐爛。

明日預告

說到了測試程式碼的抽離與分層,在 Web UI 自動化測試領域中,最知名且廣為人知的設計模式莫過於 Page Object Pattern (POM)

然而,許多 QA 雖然用了 POM,卻寫出了幾千行的「肥大頁面類別(God Page Class)」,甚至把 Page Object 變成了另一種維護災難。

明天 Day 9,我們就來深度探討:《 Day 9|Page Object 到底該怎麼用?從濫用反思到 Component Object 實戰 》


上一篇
Day 7|一個測試案例應該負責多少事情?論測試案例的粒度與獨立性
下一篇
Day 9|Page Object到底該怎麼用?從濫用反思到 Component Object 實戰
系列文
從脆弱腳本到可信任測試平台:自動化測試架構30天9
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言