BDD(行為驅動開發)

是什麼?

BDD(Behavior-Driven Development)是 Dan North 提出的開發方法論,從使用者行為的角度定義軟體的預期行為,使用 Given-When-Then 格式撰寫可執行的規格。

ℹ️BDD vs TDD

TDD 從技術角度出發(測試函式),BDD 從使用者行為出發(測試場景)。BDD 是 TDD 的延伸和補充,不是取代。

核心觀念

常見誤區

⚠️BDD 的陷阱

  • BDD 不只是 Gherkin:BDD 的核心是團隊協作和行為思維,Gherkin 只是工具。沒有協作的 Gherkin 就是多餘的語法
  • 場景寫太技術化Given database has record with id=1 不是 BDD。用業務語言:Given a registered customer
  • 場景太多太細:不是每個功能都需要 BDD 場景。只用在有溝通價值的核心業務流程
  • Step Definition 變成 God Class:每個 Step 應該簡短,複雜邏輯放到 Page Object 或 Helper

BDD 流程

1

Discovery(探索)

PM、QA、Dev 一起討論功能需求,用具體例子釐清行為

2

Formulation(定義)

把討論結果寫成 Given-When-Then 格式的場景

3

Automation(自動化)

用 SpecFlow/Cucumber 把場景變成可執行的測試

4

Implementation(實作)

用 TDD 實作功能,讓 BDD 場景通過

5

Living Documentation

場景檔案成為持續更新的活文件,所有人都看得懂

程式碼範例

Gherkin 場景(Feature File)

gherkin
Feature: 購物車結帳
  作為一個線上購物的顧客
  我想要在購物車結帳
  以便完成購買流程
 
  Scenario: 一般顧客購買單一商品
    Given 顧客 "Alice" 已登入
    And 購物車中有 1 件 "TypeScript 入門書" 單價 500 元
    When 顧客點擊結帳
    Then 訂單總額應為 500 元
    And 訂單狀態應為 "已建立"
 
  Scenario: VIP 顧客享有折扣
    Given VIP 顧客 "Bob" 已登入
    And 購物車中有 1 件 "TypeScript 入門書" 單價 500 元
    When 顧客點擊結帳
    Then 訂單總額應為 400 元
    And 應顯示 "VIP 折扣 20%"

C#(xUnit + SpecFlow)

csharp
// Step Definitions — 把 Gherkin 對應到程式碼
[Binding]
public class CheckoutSteps
{
    private Customer _customer;
    private ShoppingCart _cart;
    private Order _order;
 
    [Given(@"顧客 ""(.*)"" 已登入")]
    public void GivenCustomerLoggedIn(string name)
    {
        _customer = new Customer(name, CustomerType.Regular);
        _cart = new ShoppingCart(_customer);
    }
 
    [Given(@"VIP 顧客 ""(.*)"" 已登入")]
    public void GivenVipCustomerLoggedIn(string name)
    {
        _customer = new Customer(name, CustomerType.Vip);
        _cart = new ShoppingCart(_customer);
    }
 
    [Given(@"購物車中有 (\d+) 件 ""(.*)"" 單價 (\d+) 元")]
    public void GivenCartHasItem(int qty, string name, decimal price)
    {
        _cart.AddItem(new Product(name, price), qty);
    }
 
    [When(@"顧客點擊結帳")]
    public void WhenCustomerCheckout()
    {
        _order = _cart.Checkout();
    }
 
    [Then(@"訂單總額應為 (\d+) 元")]
    public void ThenOrderTotalShouldBe(decimal expected)
    {
        Assert.Equal(expected, _order.Total);
    }
 
    [Then(@"訂單狀態應為 ""(.*)""")]
    public void ThenOrderStatusShouldBe(string status)
    {
        Assert.Equal(status, _order.Status);
    }
}

TypeScript(Jest + Cucumber)

typescript
import { Given, When, Then } from "@cucumber/cucumber";
 
let customer: Customer;
let cart: ShoppingCart;
let order: Order;
 
Given("顧客 {string} 已登入", (name: string) => {
  customer = new Customer(name, "regular");
  cart = new ShoppingCart(customer);
});
 
Given("購物車中有 {int} 件 {string} 單價 {int} 元", (qty, name, price) => {
  cart.addItem(new Product(name, price), qty);
});
 
When("顧客點擊結帳", () => {
  order = cart.checkout();
});
 
Then("訂單總額應為 {int} 元", (expected: number) => {
  expect(order.total).toBe(expected);
});

Python(pytest + pytest-bdd)

python
from pytest_bdd import given, when, then, scenario
 
@scenario("checkout.feature", "一般顧客購買單一商品")
def test_regular_customer_checkout():
    pass
 
@given("顧客 \"Alice\" 已登入", target_fixture="cart")
def customer_logged_in():
    customer = Customer("Alice", CustomerType.REGULAR)
    return ShoppingCart(customer)
 
@given("購物車中有 1 件 \"TypeScript 入門書\" 單價 500 元")
def cart_has_item(cart):
    cart.add_item(Product("TypeScript 入門書", 500), 1)
 
@when("顧客點擊結帳", target_fixture="order")
def customer_checkout(cart):
    return cart.checkout()
 
@then("訂單總額應為 500 元")
def order_total_should_be(order):
    assert order.total == 500

關係圖

BDD(行為驅動開發)
核心格式
Given-When-Then
結構化語法
Gherkin 語法
寫成場景檔
Feature File
對應到程式碼
Step Definition
用 TDD 實作
TDD
SpecFlow / Cucumber

此圖展示 BDD 的完整流程鏈:從 Given-When-Then 格式出發,用 Gherkin 語法寫成 Feature File,透過 Step Definition 對應到測試程式碼,最終用 TDD 實作功能讓場景通過。注意:BDD 的價值不只在程式碼層,更在於 Discovery 階段的團隊溝通。

BDD vs 普通 Unit Test:何時選 BDD

| 判斷條件 | 用 BDD | 用普通 Unit Test | |----------|--------|-----------------| | 需要 PM/QA 參與討論場景 | 是 | 否 | | 核心業務流程(如結帳、退款) | 是 | 否 | | 底層工具函式、數學計算 | 否 | 是 | | 需要活文件讓非技術人員理解 | 是 | 否 | | 團隊沒有 PM/QA 協作的文化 | 否(先建文化再用工具) | 是 |

實戰補充

💡資深開發者的經驗

  • Three Amigos 會議:每個功能開始前,PM + QA + Dev 三方一起討論具體例子。這個「Discovery」階段才是 BDD 的最大價值。
  • 不是所有測試都要用 BDD:BDD 場景適合核心業務流程。底層的技術邏輯用普通的 Unit Test 就好。
  • Gherkin 的維護成本:Feature File + Step Definition 是雙倍的維護量。只在「溝通價值 > 維護成本」時使用。
  • 常用工具:C# 用 SpecFlow(已被 Reqnroll 接替),JS/TS 用 Cucumber.js,Python 用 pytest-bdd 或 Behave。

理解測驗

🤔 BDD 的 Given-When-Then 分別代表什麼?

🤔 BDD 和 TDD 的主要差異是什麼?

🤔 什麼情境最適合使用 BDD?

重點整理

💡一句話記住

口訣:「假設...當...那麼...」—— 三個人坐下來把故事說清楚,BDD 的價值在溝通不在語法。

| 概念 | 說明 | |------|------| | Given-When-Then | 前提-動作-預期結果,BDD 的核心格式 | | Gherkin | 結構化的自然語言語法 | | Feature File | 用 Gherkin 寫成的可執行規格 | | Step Definition | 把 Gherkin 對應到測試程式碼 | | 核心好處 | 促進團隊溝通、活的文件 | | 代價 | Feature + Step 雙倍維護成本,不適合底層技術測試 |

你可能也想看

TDD 與 Legacy CodeTDD 反模式

按 ← → 鍵切換課程