iT邦幫忙

2025 iThome 鐵人賽

DAY 26
0
Vue.js

Vue 全攻略:30 天技能樹養成系列 第 26

【Day 26】測試金字塔:單元、整合與 E2E 測試的權衡

  • 分享至 

  • xImage
  •  

聯繫我

如果有任何問題或建議,歡迎隨時聯繫我:

前言

過去幾天,我們一頭栽進了「單元測試」的世界。我們學會了如何像個鐘錶師傅一樣,細心地檢測每一個微小的齒輪(函式)和零件(元件),確保它們都運作得分毫不差。

但這引出了一個重要的問題:

一個由無數個完美零件組裝起來的系統,就保證能完美運作嗎?

答案是:不一定

打個比方:你可能擁有世界上最頂級的引擎、最順滑的變速箱、和抓地力最強的輪胎(所有零件的單元測試都完美通過)。但是,如果連接引擎和變速箱的螺絲尺寸不對,這台車依然動彈不得。要發現這個問題,你必須把引擎和變速箱整合起來測試。

更進一步,就算車子能動了,它能在真實的賽道上順利跑完一圈嗎?這就需要一次端到端 (End-to-End) 的完整測試。

這就是我們今天要探討的主題:測試金字塔 (The Testing Pyramid)。它是一個經典的模型,幫助我們理解不同測試類型之間的關係與權衡,指導我們建立一個健康、高效的測試策略。

1. 認識測試金字塔

測試金字塔是一個形象的比喻,它將軟體測試由下到上分為三層:

  • 底部 (最大塊): 單元測試 (Unit Tests)
  • 中間: 整合測試 (Integration Tests)
  • 頂部 (最小塊): 端到端測試 (End-to-End Tests)

這個金字塔結構蘊含了幾個關鍵的權衡:

層級 執行速度 維護成本 測試範疇 整合信心 數量
E2E 測試 最慢 最高 整個應用 最高 少量
整合測試 中等 中等 多個單元 中等 中量
單元測試 最快 最低 單一單元 最低 大量

一個健康的測試策略,其不同類型測試的數量分佈,應該要像一個金字塔,而不是一個甜筒(大量昂貴的 E2E 測試)或沙漏(缺乏整合測試)。

2. 金字塔底層:單元測試 (Unit Tests)

  • 這是什麼?:這就是我們過去幾天一直在做的事。專注於測試一個獨立、隔離的「單元」,例如一個函式或一個 Vue 元件。
  • 測試範疇:極度狹窄。在測試中,我們會用 Mock 將所有外部依賴(API, Store, 其他元件)全部隔離開。
  • 優點:執行速度極快,能精準定位問題(測試失敗了,你就知道是哪個函式出錯),撰寫和維護成本低。
  • 缺點:無法保證單元之間協作的正確性。它只保證零件本身是好的,不保證組裝後沒問題。
  • 工具Vitest, Jest

3. 金字塔中層:整合測試 (Integration Tests)

  • 這是什麼?:驗證多個「單元」能否正確地協同工作。
  • 測試範疇:比單元測試更廣。它可能包含一個父元件和它的幾個子元件,或是一個頁面與它互動的 Pinia Store。
  • Vue 中的例子
    1. 測試一個表單頁面,該頁面由多個 BaseInputBaseButton 原子元件組成。
    2. 測試一個商品列表頁面,它從 Pinia Store 讀取商品資料並渲染出一個 ProductCard 元件列表。
    3. 我們在 Day 24 用 Testing Library 寫的 LoginForm 測試,其實已經算是一個小型的整合測試,因為它測試了 label, input, button 這些單元如何整合起來完成一次登入操作。
  • 優點:在「速度」與「信心」之間取得了很好的平衡。能有效地發現單元之間的「接口」問題。
  • 缺點:比單元測試慢,且當測試失敗時,問題的根源可能在任何一個被整合的單元中,除錯稍加困難。
  • 工具Vitest + @testing-library/vue 是進行整合測試的絕佳組合。

4. 金字塔頂層:端到端測試 (E2E Tests)

  • 這是什麼?:從使用者的視角,模擬一個完整的操作流程,測試整個應用程式。
  • 測試範疇:最廣。它會在一個真實的瀏覽器中,打開你的網站,然後像真人一樣去點擊、輸入、滾動。它會和你真實的後端 API 進行互動(或者是一個高擬真度的 Mock 伺服器)。
  • 一個 E2E 測試案例的劇本可能像這樣
    1. cy.visit('/login'):打開登入頁面。
    2. cy.get('#username').type('my-user'):在使用者名稱欄位輸入文字。
    3. cy.get('#password').type('my-pass'):在密碼欄位輸入文字。
    4. cy.get('button[type=submit]').click():點擊登入按鈕。
    5. cy.url().should('include', '/dashboard'):斷言頁面跳轉到了儀表板。
    6. cy.contains('Welcome, my-user'):斷言頁面上出現了歡迎訊息。
  • 優點:提供最高級別的信心。一個 E2E 測試通過,代表這個核心功能在接近真實的環境下是可用的。
  • 缺點
    • :啟動瀏覽器、等待頁面載入、等待 API 回應,每個測試都可能耗時數秒甚至數十秒。
    • 脆弱 (Brittle):容易因為一些無關緊要的 UI 變動或網路波動而失敗。
    • 昂貴:撰寫和維護的成本非常高。
  • 工具Cypress, Playwright 是這個領域的兩大巨頭。

5. 如何取得平衡?

金字塔模型給我們的啟示是:不要試圖用 E2E 測試覆蓋所有細節!這是一個常見且昂貴的錯誤,被稱為「冰淇淋甜筒反模式 (Ice Cream Cone Anti-Pattern)」。

一個健康的策略應該是:

  • 為你的工具函式、複雜的 Composable、獨立的演算法撰寫大量的、快速的單元測試
  • 為你的元件在不同 Props/Slots 下的渲染結果撰寫大量的單元測試
  • 為幾個元件組合起來的區塊、或與 Store 互動的頁面,撰寫適量的整合測試
  • 只為你應用程式中最關鍵、最核心的幾個使用者旅程(例如:註冊、登入、購物車結帳),撰寫少量的 E2E 測試,作為最後的防線。

本篇自我挑戰

  1. 分類練習:回顧一下你為專案寫的測試,試著將它們歸類到金字塔的某一層。為什麼你會這樣分類?
  2. 思考 E2E 場景:找出你的應用程式中 1~3 個最重要的使用者流程。如果讓你來寫 E2E 測試,你會選擇哪些流程?試著用文字把這個「劇本」寫下來。
  3. 開開眼界:(選做) 前往 CypressPlaywright 的官方網站,觀看它們的介紹影片,感受一下 E2E 測試工具的強大之處。

總結

今天,我們從單一的測試層級中跳脫出來,鳥瞰了整個自動化測試的宏觀戰略。

  • 單元測試:快、狠、準,是測試策略的基石。
  • 整合測試:承上啟下,確保零件能正確組裝。
  • E2E 測試:終極保障,確保核心體驗在真實環境下暢通無阻。

沒有哪一種測試是萬靈丹。一個成熟的工程團隊,會善用不同測試的優缺點,將它們合理地配置在金字塔的各個層級,以最小的成本,換取最大的信心。

明天,我們將回到程式碼,探討 Vue 專案中一個非常實用的主題:效能優化 (Performance Optimization)

本日關鍵字回顧

  • 測試金字塔 (Testing Pyramid)
  • 單元測試 (Unit Test)
  • 整合測試 (Integration Test)
  • 端到端測試 (End-to-End Test)
  • 測試範疇 (Scope)
  • 整合信心 (Confidence)
  • Cypress
  • Playwright
  • 冰淇淋甜筒反模式 (Ice Cream Cone Anti-Pattern)

上一篇
【Day 25】給測試一個乾淨的世界:Mocking API 請求
系列文
Vue 全攻略:30 天技能樹養成26
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言