cover

TDD / BDD / SDD:三種驅動開發的思維模式

重點不是「先寫測試」,而是「用什麼來定義正確」。

為什麼要談這個

很多人把 TDD 理解為「先寫測試再寫功能」,然後覺得太慢、太麻煩、不實際。

這是因為他們只看到了手法,沒看到背後的哲學

TDD / BDD / SDD 本質上在回答同一個問題:「你怎麼知道你寫的東西是對的?」

三者的差別在於:「誰來定義什麼叫對?」


三種「驅動」的核心差異

graph TD
    A[一個功能需求] --> B{由誰定義正確?}
    B -->|開發者視角| C[TDD<br/>用程式碼的行為定義]
    B -->|使用者視角| D[BDD<br/>用商業場景定義]
    B -->|合約視角| E[SDD<br/>用規格文件定義]

    style C fill:#4CAF50,color:#fff
    style D fill:#2196F3,color:#fff
    style E fill:#FF9800,color:#fff
TDDBDDSDD
驅動力測試案例行為場景規格文件
語言程式碼(assert)自然語言(Given-When-Then)結構化文件(OpenAPI, Proto)
誰最該看懂開發者PM / QA / 開發者所有利害關係人
定義「正確」的基準所有測試通過所有場景覆蓋實作符合規格
最大價值強迫你想清楚邊界條件讓技術與商業對齊先定義合約再分頭實作

TDD — 用失敗的測試來思考

核心循環:Red → Green → Refactor

1. Red    — 寫一個會失敗的測試(因為功能還沒實作)
2. Green  — 用最簡單的方式讓測試通過
3. Refactor — 在測試保護下重構,讓 code 變乾淨

TDD 真正在教你的事:

  • 在寫功能之前,先想清楚這個功能的邊界是什麼。 輸入是什麼?輸出是什麼?null 怎麼處理?空陣列呢?
  • 「最簡單的方式讓測試通過」不是偷懶,是刻意的。 它逼你一次只解決一個問題,避免過度設計。
  • 測試不是事後補的安全網,而是設計工具。 如果你發現測試很難寫,通常代表你的 API 設計有問題。

什麼時候 TDD 特別有用:

  • 演算法邏輯、資料轉換、工具函式
  • 你很清楚輸入輸出,但邊界條件很多的場景

什麼時候 TDD 不太適合:

  • UI 開發(行為難以用 assert 定義)
  • 探索性開發(你還不知道要什麼)

BDD — 用場景來對齊期望

核心格式:Given / When / Then

Feature: 使用者登入
 
  Scenario: 正確帳密登入
    Given 使用者已註冊,帳號 "terry@example.com"
    When 使用者用正確密碼登入
    Then 應該看到首頁
    And 導覽列顯示使用者名稱
 
  Scenario: 密碼錯誤
    Given 使用者已註冊
    When 使用者用錯誤密碼登入
    Then 應該看到「帳號或密碼錯誤」的提示
    And 不應該被導向首頁

BDD 真正在教你的事:

  • 需求不是模糊的一句話,而是一組可驗證的場景。 當 PM 說「要有登入功能」,BDD 逼你問:「登入失敗要顯示什麼?連續失敗三次呢?」
  • 用人話寫測試,所有人都能參與 review。 QA 可以補場景、PM 可以確認這是不是他要的行為。
  • 場景就是活的文件。 它永遠跟程式碼同步,不像 spec 文件寫完就過時。

什麼時候 BDD 特別有用:

  • 功能型需求(使用者登入、購物車結帳、權限控制)
  • 跨角色溝通成本高的團隊

常見工具: Cucumber、Jest + Gherkin、Behave (Python)


SDD — 用規格合約來定義邊界

核心概念:先定義介面,再分頭實作

# OpenAPI 規格範例
paths:
  /users/{id}:
    get:
      summary: 取得使用者資料
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '404':
          description: 使用者不存在

SDD 真正在教你的事:

  • 合約是團隊協作的基礎。 前後端可以同時開工,因為介面已經定義好了。
  • 規格即文件、即測試、即 mock。 從 OpenAPI 可以自動生成 mock server、client SDK、API 文件。
  • 強迫你在寫 code 之前就想清楚 API 的形狀。 欄位名稱、型別、必填與否、錯誤碼——這些都在寫第一行程式碼之前就定義好。

什麼時候 SDD 特別有用:

  • 前後端分離的團隊
  • 微服務之間的溝通(gRPC / Protocol Buffers)
  • 公開 API(你不能隨便改介面)

三者不互斥,而是不同層次

一個成熟的專案可能同時使用:

SDD — 定義 API 合約(團隊對齊用)
 ↓
BDD — 定義功能場景(需求驗證用)
 ↓
TDD — 定義單元行為(實作品質用)

就像蓋房子:SDD 是藍圖、BDD 是「住進去之後什麼體驗」、TDD 是「每根柱子的承重夠不夠」。


你該怎麼選?

不要問「我該用 TDD 還是 BDD」,而是問:

你現在的痛點適合的方向
寫完功能才發現邊界條件沒處理TDD — 先想邊界再寫功能
PM 驗收時說「這不是我要的」BDD — 用場景對齊期望
前後端一直在等對方SDD — 先定義合約再分頭做
重構很怕改壞東西TDD — 測試就是安全網
文件永遠跟程式碼不同步SDD — 規格就是文件

反思問題

  1. 你現在的專案,「正確」是由什麼定義的? 是 PM 驗收時的口頭確認?還是有明確的場景或測試?
  2. 你上次因為「邊界條件沒想到」而出 bug 是什麼時候? TDD 的 Red 階段就是在逼你想這些。
  3. 你的 API 文件跟實際行為一致嗎? 如果不確定,SDD 可能是你需要的。
  4. AI 可以幫你生成測試、場景、規格,但你知道該生成什麼嗎? 這才是你要掌握的。

延伸閱讀