# 關於 BDD 與 Gherkin > Behavior-Driven Development,行為驅動開發 BDD 是一種軟體開發方法論,從 TDD(測試驅動開發)演進而來。它強調透過「行為」來描述系統需求,關注軟體應該「做什麼」,而不只是「怎麼做」。 **核心理念:** - 以行為為中心,從用戶和業務需求的角度描述系統行為 - 讓 PM、RD、QA 使用同一種語言溝通 - 將需求直接轉換為可執行的測試 BDD 解決了傳統開發中 **「 需求翻譯 」** 的問題,讓所有角色對需求有一致的理解。 ## 什麼是 Gherkin? Gherkin 是實現 BDD 的一種具體的規格語言,可以這樣理解: - BDD = 開發方法論( 概念層面 ) - Gherkin = 描述語言( 實踐工具 ) ### Gherkin 的特性 1. 領域特定語言(DSL) -- 使用自然語言,但有明確的語法規則 -- 人類可讀,機器可執行 2. 結構化語法 ```gherkin= Feature: 功能描述 Rule: 業務規則 Scenario/Example: 測試場景 Given: 給定(前置條件) When: 當(執行操作) Then: 那麼(預期結果) And: 和(連接同類步驟) ``` 3. 可執行性 -- Gherkin 文件可被 Cucumber、SpecFlow、Behave 等工具解析 -- 連接到實際的測試代碼(Step Definitions) :::info Gherkin 核心關鍵字 | 關鍵字 | 用途 | 說明 | |--------|------|------| | **Feature** | 功能特性 | 描述要實現的功能模組 | | **Rule** | 業務規則 | 原子化的業務邏輯單元 | | **Scenario** | 具體場景 | 描述單一測試情境 | | **Scenario Outline** | 參數化場景 | 用表格覆蓋多組測資 | | **Given** | 前置條件 | 設定初始狀態 | | **When** | 執行動作 | 觸發的事件或操作 | | **Then** | 預期結果 | 驗證的輸出 | | **And / But** | 連接步驟 | 連接多個同類步驟 | | **Background** | 共用前置 | 所有場景共享的前置條件 | | **Examples** | 測試數據表 | 提供多組參數化數據 | ::: --- ## Gherkin 撰寫實務範例 ### **▶ 基礎層:Feature + Scenario(正例 + 反例)** > **適用時機:** 驗證單一功能的基本行為 ```gherkin= Feature: 查詢商品價格 使用者可以查詢系統中任一商品的當前價格 Scenario: 查詢已上架商品的價格(正例) Given 商品 "可樂" 存在於系統中,價格為 30 元 When 使用者查詢商品 "可樂" 的價格 Then 系統回傳價格為 30 元 Scenario: 查詢不存在的商品(反例) When 使用者查詢商品「不存在的商品」的價格 Then 操作失敗 ``` **撰寫要點:** - 使用雙引號「 `""` 」標記參數 - 數字可以直接使用,無需引號 - 反例的 Given 可以省略(無前置條件時) - 應包含正例與反例 <br /> --- ### **▶ 中階層:Feature + Rule + Scenario(原子化規則)** > 適用時機:功能包含多條業務規則 > ```gherkin= Feature: 計算訂單折扣 Rule: 滿額折價 當單筆訂單金額達到門檻時,系統應給予相應折扣 Example: 訂單金額達到折扣門檻 Given 系統設定滿 1000 元折 100 元 And 購物車中有商品總額為 1200 元 When 使用者結帳 Then 折扣金額為 100 元 And 最終金額為 1100 元 Example: 訂單金額未達折扣門檻 Given 系統設定滿 1000 元折 100 元 And 購物車中有商品總額為 800 元 When 使用者結帳 Then 折扣金額為 0 元 And 最終金額為 800 元 ``` **原子化原則:** - 每條 Rule 是一個不可分割的業務邏輯單元 - 每個 Feature 對應開發中要實作的一個邏輯模組 - Rule 幫助拆解複雜功能為獨立規則 <br /> --- ### **▶ 進階層:Feature + Rule + Scenario Outline + Examples** > 適用時機:需要驗證多組測資和邊界條件 ```gherkin= Feature: 會員等級折扣計算 Rule: 不同會員等級享有不同折扣率 系統根據會員等級自動計算折扣價格 Scenario Outline: 查詢商品價格並套用會員折扣 Given 商品 "可樂" 原價為 30 元 And 會員「<會員名稱>」的等級為「<會員等級>」 When 會員「<會員名稱>」查詢商品 "可樂" 的價格 Then 系統回傳折扣後價格為 <折扣價> 元 Examples: 一般場景 | 會員名稱 | 會員等級 | 折扣價 | | 小明 | 一般會員 | 30 | | 小華 | 銀卡會員 | 27 | | 小李 | 金卡會員 | 24 | Examples: 邊界場景 | 會員名稱 | 會員等級 | 折扣價 | 備註 | | 小王 | 白金會員 | 21 | 最高折扣 | | 小陳 | 未登入 | 30 | 未登入無折扣 | | 小張 | 黑名單 | 錯誤 | 黑名單禁止查詢價格 | ``` **優勢:** - 避免重複撰寫相似場景 - 清楚呈現不同輸入與輸出的關係 - 可分組測試數據(一般場景 vs 邊界場景) <br /> ## Gherkin 進階技巧 **▶ Background:提煉共用前置步驟** > 適用時機:多個場景有相同的前置條件 ```gherkin! Feature: 會員下訂單 會員必須先登入,才能將商品加入購物車並下訂 Background: Given 會員 "小明" 已註冊,帳號為「ming@example.com」 And 會員 "小明" 已登入系統 And 商品 "可樂" 存在於系統中,價格為 30 元 And 商品 "洋芋片" 存在於系統中,價格為 50 元 Scenario: 會員下訂單包含單一商品 Given 會員 "小明" 將商品 "可樂" 加入購物車,數量為 2 When 會員 "小明" 下定訂單 Then 訂單的訂單金額總額為 60 元 And 訂單的擁有者為會員 "小明" Scenario: 會員下訂單包含多項商品 Given 會員 "小明" 將商品 "可樂" 加入購物車,數量為 3 And 會員 "小明" 將商品 "洋芋片" 加入購物車,數量為 2 When 會員 "小明" 下定訂單 Then 訂單的訂單金額總額為 190 元 And 訂單的擁有者為會員 "小明" ``` **注意事項:** - Background 會在每個 Scenario 執行前運行 - 只放共用的前置條件,不要放測試邏輯 --- ### **▶ Docstring:傳遞複雜結構** > 適用時機:需要傳遞 JSON、XML、Markdown 等多行文本 ```gherkin= Scenario: 建立會員資料 Given 系統接收到以下 JSON 資料 """ { "name": "小明", "email": "ming@example.com", "preferences": { "newsletter": true, "notifications": false } } """ When 建立新會員 Then 會員資料儲存成功 ``` **格式規則:** - 使用三個雙引號 """ 包裹 - 保持原始格式(包括縮排和換行) --- ### **▶ Data Table:指定批次參數** > 適用時機:需要一次性設定多筆結構化資料 ```gherkin= Scenario: 批次新增商品 Given 系統中有以下商品 | 商品名稱 | 價格 | 庫存 | | 可樂 | 30 | 100 | | 洋芋片 | 50 | 50 | | 礦泉水 | 20 | 200 | When 使用者查詢所有商品 Then 系統回傳 3 筆商品資料 ``` **與 Examples 的區別:** - Data Table:在單一步驟中傳遞多筆資料 - Examples:定義多組完整的場景參數 --- ### **▶ 使用星號(*)取代關鍵字 (And)** ```gherkin= Scenario: 完成購物 Given 我正在購物 * 我有雞蛋 * 我有牛奶 * 我有奶油 When 我檢查清單 Then 我不需要其他東西 ``` **何時使用:** - 多個連續的 And 步驟 - 列舉類型的步驟 - 強調步驟的並列關係 <br /> ## 如何選擇合適的架構? **問題一:這個功能有多條業務規則需要處理嗎?** - 否 → 使用 Feature + Scenario - 是 → 使用 Feature + Rule + Scenario **問題二:同一條規則需要驗證多組測資嗎?** - 否 → 維持 Scenario - 是 → 升級 Scenario Outline + Examples **問題三:多個場景有相同的前置步驟嗎?** - 是 → 加入 Background ``` 你的功能有多條業務規則嗎? ├─ 否 → 使用【基礎層】Feature + Scenario └─ 是 → 使用【中階層】Feature + Rule + Scenario │ └─ 需要驗證多組測資嗎? ├─ 否 → 維持 Scenario └─ 是 → 升級【進階層】Scenario Outline + Examples 有重複的前置步驟嗎? └─ 是 → 加入 Background 需要批次資料嗎? └─ 是 → 使用 Data Table 需要傳遞複雜結構(JSON/XML)嗎? └─ 是 → 使用 Docstring ``` ## BDD 實踐 ### 實踐流程 ``` 1. 三方會議(Three Amigos) PM + RD + QA 共同討論需求 ↓ 2. 用 Gherkin 撰寫場景 將需求轉換為 Given-When-Then 格式 ↓ 3. 開發 Step Definitions 將 Gherkin 步驟連接到實際代碼 ↓ 4. 執行測試 Cucumber/SpecFlow/Behave 執行測試 ↓ 5. 持續更新 需求變更時同步更新 Gherkin 文件 ``` ### 撰寫原則 #### 1. 使用業務語言,避免技術細節 -- ❌ `Given 資料庫中 users 表有一筆 id=1 的記錄` -- ✅ `Given 會員 "小明" 已註冊` #### 2. 每個 Scenario 保持獨立 -- 不依賴其他場景的執行結果 -- 可以任意順序執行 #### 3. 一個 Scenario 只驗證一件事 -- 避免過長的場景 -- 拆分複雜邏輯為多個 Rule #### 4. 善用參數化 -- 相似場景使用 Scenario Outline -- 減少重複代碼 #### 5. 保持 Step 的原子性 -- 每個步驟做一件事 -- 便於重用和維護 #### ※ 常見陷阱 - 過度技術化 - Gherkin 應該讓非技術人員也能理解 - 步驟耦合 - Given/When/Then 步驟互相依賴內部狀態 - 缺乏具體性 - 使用模糊的詞彙如「正確的」「適當的」 - 過度使用 Background - 導致場景難以獨立理解 <br /> ## 總結 - BDD 是一種開發方法論,強調用行為描述需求 - Gherkin 是實現 BDD 的標準化語言 - 兩者的關係:沒有 BDD,Gherkin 只是語法;沒有 Gherkin,BDD 難以標準化實踐 - 選擇合適的架構層次(基礎/中階/進階)取決於功能複雜度 - 善用進階技巧(Background、Data Table、Docstring)提升可維護性 - BDD 的核心價值在於讓所有角色對需求有一致的理解
×
Sign in
Email
Password
Forgot password
or
Sign in via Google
Sign in via Facebook
Sign in via X(Twitter)
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
Continue with a different method
New to HackMD?
Sign up
By signing in, you agree to our
terms of service
.