export-feature-file
SKILL.md
Export Feature File
目的
產出可直接被 BDD 測試框架執行的 Feature File(.feature),實現「測試即文件」(Living Documentation)。
支援的測試框架
| 語言/平台 | 測試框架 | Cucumber Expression {} |
|---|---|---|
| .NET | Reqnroll | ✅ 原生支援 |
| Java | Cucumber-JVM | ✅ 原生支援 |
| JavaScript/TypeScript | Cucumber.js | ✅ 原生支援 |
| Python | Behave | ❌ 使用框架原生語法 |
| Ruby | Cucumber | ✅ 原生支援 |
| Go | Godog | ✅ 原生支援 |
格式定義
Feature: 功能名稱
功能描述(說明這個功能的目的)
Scenario: 情境描述(單一固定案例)
Given 前置條件
When 觸發動作
Then 預期結果
Scenario Outline: 情境描述(多組測試資料)
Given 前置條件 <參數A>
When 觸發動作 <參數B>
Then 預期結果 <參數C>
Examples:
| 參數A | 參數B | 參數C |
| 值1 | 值2 | 值3 |
| 值4 | 值5 | 值6 |
| 關鍵字 | 用途 | 範例 |
|---|---|---|
| Feature | 功能名稱與描述 | Feature: 用戶登入 |
| Scenario | 單一固定測試案例 | Scenario: 用戶成功登入 |
| Scenario Outline | 參數化測試案例,搭配 Examples | Scenario Outline: 登入驗證 |
| Examples | 測試資料表格,搭配 Scenario Outline | 見範例 |
| Given | 前置條件 / 初始狀態 | Given 用戶已註冊帳號 "test@example.com" |
| When | 觸發的動作或事件 | When 用戶點擊登入按鈕 |
| Then | 預期的結果 | Then 系統導向至首頁 |
| And | 延續上一個關鍵字(可選) | And 顯示歡迎訊息 |
範例
範例 1:用戶登入
輸入(程式碼邏輯):
// 檢查帳號密碼,正確則導向首頁,錯誤則顯示錯誤訊息
// 連續錯誤 3 次則鎖定帳號
輸出(Feature File):
Feature: 用戶登入
用戶透過帳號密碼進行身份驗證,以存取系統功能
Scenario: 用戶成功登入
Given 用戶已註冊帳號 "test@example.com"
And 帳號未被鎖定
When 用戶輸入正確的帳號密碼
Then 系統導向至首頁
Scenario: 用戶登入失敗
Given 用戶已註冊帳號 "test@example.com"
When 用戶輸入錯誤的密碼
Then 系統停留在登入頁面
And 顯示錯誤訊息 "帳號或密碼錯誤"
Scenario Outline: 連續登入失敗鎖定帳號
Given 用戶已連續輸入錯誤密碼 <前次失敗> 次
When 用戶第 <本次> 次輸入錯誤密碼
Then 帳號狀態為 "<結果>"
Examples:
| 前次失敗 | 本次 | 結果 |
| 1 | 2 | 正常 |
| 2 | 3 | 鎖定 |
範例 2:購物車
輸入(需求描述):
用戶可以將商品加入購物車,數量不可超過庫存,
結帳時計算總金額並套用折扣碼
輸出(Feature File):
Feature: 購物車管理
用戶可以管理購物車內的商品,並在結帳時套用優惠
Scenario Outline: 加入商品至購物車
Given 商品庫存為 <庫存> 件
When 用戶將該商品加入購物車 <數量> 件
Then 購物車商品數量為 <數量>
And 庫存剩餘 <剩餘> 件
Examples:
| 庫存 | 數量 | 剩餘 |
| 10 | 1 | 9 |
| 10 | 5 | 5 |
Scenario: 加入商品超過庫存數量
Given 商品庫存為 5 件
When 用戶嘗試將該商品加入購物車 10 件
Then 系統拒絕此操作
And 顯示錯誤訊息 "庫存不足"
Scenario Outline: 套用折扣碼
Given 購物車總金額為 <原價> 元
And 折扣碼 "<折扣碼>" 可折抵 <折扣>%
When 用戶輸入折扣碼 "<折扣碼>"
Then 總金額更新為 <結果> 元
Examples:
| 原價 | 折扣碼 | 折扣 | 結果 |
| 1000 | SAVE10 | 10 | 900 |
| 1000 | SAVE20 | 20 | 800 |
輸出規範
- 必須包含 Feature:每個輸出都以 Feature 開頭,說明功能名稱與目的
- 相關 Scenario 歸屬同一 Feature:將相關的測試情境組織在同一個 Feature 下
- 每個 Scenario 聚焦於單一行為
- 專注在有價值的行為:不求詳盡,只描述最關鍵的業務規則
- 使用業務語言,但可提及 API、DB 等技術元素作為測試驗證點
- Given/When/Then 各自獨立成行,保持可讀性
- And 為可選,僅當條件或結果有多項時才使用
- 使用具體數值:提供實際的測試資料,不使用抽象變數
- 參數化測試使用 Scenario Outline:
- 當同一行為需要多組測試資料時,使用
Scenario Outline+Examples - 參數使用
<參數名稱>格式 - Examples 表格提供具體測試資料
- 當同一行為需要多組測試資料時,使用
- 字串參數用雙引號包覆:如
"test@example.com"、"SAVE10" - 沙漏原則 - When 最小化:
- When 越小越好,理想情況只有一行
- 將操作步驟移至 Given
- When 只保留最關鍵的觸發點
- 輸出後更新指定文檔:將產出的內容寫入用戶指定的
.feature檔案
Step Definitions 風格規範
Cucumber Expression(統一使用 {} 格式)
框架原生支援 Cucumber Expression 時,使用 {string}、{int} 等 {} 格式。
框架不原生支援時(如 Python Behave、PHP Behat),使用該框架的原生參數語法,不勉強套用。
| 比較項目 | Regex 格式(禁用) | Cucumber Expression 格式(採用) |
|---|---|---|
| 字串參數 | @"帳號 ""(.*)""" |
"帳號 {string}" |
| 整數參數 | @"共 (\d+) 筆" |
"共 {int} 筆" |
| 浮點數參數 | @"金額 ([\d.]+)" |
"金額 {float}" |
| 無參數 | @"用戶點擊登入" |
"用戶點擊登入" |
Step Definitions 對應提示
產出 Feature File 後,開發者需依據所使用的測試框架撰寫對應的 Step Definitions。
Scope 綁定規範
Step Definitions 必須透過 Scope 機制明確綁定至對應的 Feature,避免跨 Feature 的步驟定義衝突。
| 框架 | Scope 語法 | 範例 |
|---|---|---|
| .NET (Reqnroll) | [Scope(Feature = "Feature 名稱")] |
[Scope(Feature = "用戶登入")] |
| Java (Cucumber-JVM) | 不支援 Scope,透過 Glue 路徑區隔 | @CucumberOptions(glue = "steps.login") |
| JavaScript/TypeScript | 不支援 Scope,透過模組目錄區隔 | features/login/step_definitions/ |
| Python (Behave) | 不支援 Scope,透過 steps 目錄區隔 | features/steps/login_steps.py |
Scope 的 Feature 名稱需與
.feature檔案中的Feature:標題完全一致。
.NET (Reqnroll)
// Why: [Scope] 將 Step Definitions 綁定至指定 Feature,避免跨 Feature 的步驟定義衝突
// Syntax: Feature 名稱需與 .feature 檔案中的 Feature 標題完全一致
[Scope(Feature = "用戶登入")]
[Binding]
public class LoginSteps
{
[Given("用戶已註冊帳號 {string}")]
public void Given用戶已註冊帳號(string email) { /* 準備測試資料 */ }
[When("用戶輸入正確的帳號密碼")]
public void When用戶輸入正確的帳號密碼() { /* 執行登入 */ }
[Then("待發送清單應包含 {int} 筆資料")]
public void Then待發送清單應包含N筆資料(int expectedCount) { /* 驗證筆數 */ }
[Then("系統導向至首頁")]
public void Then系統導向至首頁() { /* 驗證導向 */ }
}
Java (Cucumber-JVM)
public class LoginSteps {
@Given("用戶已註冊帳號 {string}")
public void 用戶已註冊帳號(String email) { /* 準備測試資料 */ }
@When("用戶輸入正確的帳號密碼")
public void 用戶輸入正確的帳號密碼() { /* 執行登入 */ }
@Then("待發送清單應包含 {int} 筆資料")
public void 待發送清單應包含N筆資料(int expectedCount) { /* 驗證筆數 */ }
@Then("系統導向至首頁")
public void 系統導向至首頁() { /* 驗證導向 */ }
}
JavaScript/TypeScript (Cucumber.js)
import { Given, When, Then } from '@cucumber/cucumber';
Given('用戶已註冊帳號 {string}', function (email: string) { /* 準備測試資料 */ });
When('用戶輸入正確的帳號密碼', function () { /* 執行登入 */ });
Then('待發送清單應包含 {int} 筆資料', function (expectedCount: number) { /* 驗證筆數 */ });
Then('系統導向至首頁', function () { /* 驗證導向 */ });
Python (Behave) — 使用框架原生語法
from behave import given, when, then
# Why: Behave 不原生支援 Cucumber Expression,使用框架自有的參數語法
# Syntax: 字串參數用 "{param}" 雙引號包覆,整數參數用 {param:d} 加型別後綴
@given('用戶已註冊帳號 "{email}"')
def step_impl(context, email): pass # 準備測試資料
@when('用戶輸入正確的帳號密碼')
def step_impl(context): pass # 執行登入
@then('待發送清單應包含 {expected_count:d} 筆資料')
def step_impl(context, expected_count): pass # 驗證筆數
@then('系統導向至首頁')
def step_impl(context): pass # 驗證導向
檔案命名規範
- 使用
.feature副檔名 - 檔名使用 PascalCase 或 kebab-case
- 範例:
UserLogin.feature、shopping-cart.feature
Weekly Installs
1
Repository
ting-s515/skillsFirst Seen
12 days ago
Security Audits
Installed on
mcpjam1
claude-code1
replit1
junie1
windsurf1
zencoder1