跳至主要内容

實例化規格 (Specification by Example) 目錄

本目錄包含所有 SBE 層級的詳細測試場景,按 Epic 和 User Story 分組。

什麼是 SBE?

實例化規格 (Specification by Example) 是一種協作方法,使用具體的範例來說明系統應如何運作。

SBE 的核心價值

  • 消除歧義 - 用具體數據取代抽象描述
  • 可執行文檔 - 範例可直接轉為自動化測試
  • 共同理解 - 產品、開發、測試對需求有一致認知
  • 回歸測試 - 範例成為長期的驗證基準

SBE 場景索引

Epic 2: 訂單管理

(其他 Epic 與 User Stories 待補充)


SBE 文檔模板

創建新的 SBE 場景文檔時,請使用以下模板:

# Scenario N: {場景名稱}

> **User Story**: [US-XXX: 標題](../../user-stories/epic-N/US-XXX-title.md)

## Given: 系統初始狀態

### 已登入用戶
\`\`\`json
{
"userId": "user-001",
"role": "ROLE_NAME",
"tenantId": "tenant-abc",
"name": "使用者姓名"
}
\`\`\`

### 現有資料
(描述資料庫中的預存數據,使用 JSON 格式)

#### 客戶資料
\`\`\`json
{
"customerId": "cust-123",
"name": "客戶名稱",
"type": "INDIVIDUAL",
...
}
\`\`\`

#### 商品資料
\`\`\`json
[
{
"productId": "prod-001",
"name": "商品名稱",
"basePrice": 1200,
...
}
]
\`\`\`

## When: 執行操作

### API 請求
\`\`\`http
POST /api/v1/{resource}
Authorization: Bearer {token}
Content-Type: application/json

{
"field1": "value1",
"field2": "value2",
...
}
\`\`\`

### UI 操作(可選)
(如需說明 UI 操作流程)

1. 使用者點擊「XXX」按鈕
2. 填寫表單欄位 A、B、C
3. 點擊「提交」按鈕

## Then: 預期結果

### 系統響應
\`\`\`json
{
"id": "resource-001",
"status": "SUCCESS",
"data": {
...
}
}
\`\`\`

**HTTP 狀態碼**: `201 Created`

### 數據庫變更
- `table_name` 表新增 1 筆記錄
- `related_table` 表新增 N 筆記錄
- `audit_logs` 表記錄操作日誌

#### 新增的記錄範例
\`\`\`json
{
"id": "resource-001",
"tenantId": "tenant-abc",
"createdBy": "user-001",
"createdAt": "2025-10-31T10:30:00Z",
...
}
\`\`\`

### 副作用
(系統的其他行為)

- 發送通知給 XXX 角色
- 觸發 YYY 事件
- 更新 ZZZ 統計數據

## 邊界條件與錯誤場景

### 錯誤場景 1: {錯誤類型}
(測試異常情況)

#### 請求
\`\`\`http
POST /api/v1/{resource}
{
"invalidField": "value"
}
\`\`\`

#### 預期響應
\`\`\`json
{
"error": "ERROR_CODE",
"message": "錯誤訊息說明",
"field": "invalidField"
}
\`\`\`

**HTTP 狀態碼**: `400 Bad Request`

### 錯誤場景 2: {錯誤類型}
...

## 自動化測試範例

### 使用 Jest + MSW
\`\`\`typescript
describe('US-XXX: Scenario N', () => {
it('should {預期行為}', async () => {
// Arrange (Given)
const user = { userId: 'user-001', role: 'ROLE_NAME' };
const payload = { /* ... */ };

// Act (When)
const response = await api.post('/api/v1/resource', payload);

// Assert (Then)
expect(response.status).toBe(201);
expect(response.data.id).toBeDefined();
expect(response.data.tenantId).toBe('tenant-abc');
});

it('should return error when {錯誤條件}', async () => {
const invalidPayload = { /* ... */ };

await expect(
api.post('/api/v1/resource', invalidPayload)
).rejects.toMatchObject({
response: {
status: 400,
data: { error: 'ERROR_CODE' }
}
});
});
});
\`\`\`

### 使用 Cypress (E2E)
\`\`\`typescript
describe('US-XXX: Scenario N', () => {
beforeEach(() => {
cy.login('staff@example.com', 'password');
});

it('should {預期行為}', () => {
// Given
cy.visit('/resource/new');

// When
cy.get('[data-testid="field1"]').type('value1');
cy.get('[data-testid="submit-button"]').click();

// Then
cy.contains('成功訊息').should('be.visible');
cy.url().should('include', '/resource/');
});
});
\`\`\`

## 測試數據維護

### Mock API 配置
(如使用 MSW,說明如何更新 mock handlers)

檔案位置: `src/mocks/handlers/{domain}.ts`

### 種子數據
(如需要特定的測試數據,說明如何準備)

檔案位置: `src/mocks/data/seeds.ts`

## 備註
(其他重要資訊)

目錄結構

sbe/
├── epic-0/
│ └── US-001-user-login/
│ ├── scenario-1-valid-credentials.md
│ ├── scenario-2-invalid-password.md
│ └── scenario-3-locked-account.md
├── epic-2/
│ └── US-201-create-order/
│ ├── scenario-1-individual-customer.md
│ ├── scenario-2-corporate-customer.md
│ └── scenario-3-custom-project.md
└── ...

命名規範

Scenario ID

  • 格式: scenario-{編號}-{kebab-case-描述}
  • 範例: scenario-1-individual-customer.md
  • 編號從 1 開始遞增

場景命名原則

  • 使用描述性的名稱
  • 強調測試的關鍵條件
  • ✅ 好: scenario-1-individual-customer.md
  • ❌ 差: scenario-1.md

撰寫指南

1. Given - 描述前置條件

要點:

  • 使用具體的測試數據(真實的 ID、名稱、數值)
  • 用 JSON 格式呈現數據結構
  • 包含所有與場景相關的初始狀態

好的範例:

{
"customerId": "cust-123",
"name": "李大華",
"phone": "0912-345-678"
}

不好的範例:

有一個客戶

2. When - 描述執行操作

要點:

  • 提供完整的 HTTP 請求範例
  • 包含所有必要的 Headers
  • 使用真實的 Payload 數據

好的範例:

POST /api/v1/orders
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Content-Type: application/json

{
"customerId": "cust-123",
"items": [...]
}

不好的範例:

發送創建訂單的請求

3. Then - 描述預期結果

要點:

  • 提供完整的響應範例
  • 明確列出數據庫變更
  • 說明所有副作用(通知、事件等)

好的範例:

{
"orderId": "ABC-20251031-0001",
"status": "pending_confirmation",
"totalAmount": 2400
}

數據庫變更:

  • orders 表新增 1 筆記錄
  • order_items 表新增 2 筆記錄

不好的範例:

訂單創建成功

4. 邊界條件測試

每個 Scenario 都應包含至少 2-3 個錯誤場景:

  • 缺少必填欄位
  • 無效的數據格式
  • 權限不足
  • 業務規則違反

5. 可執行性

SBE 範例應該:

  • 可以直接複製到測試代碼中
  • 包含完整的 Arrange-Act-Assert 結構
  • 提供清晰的斷言條件

與 Mock API 整合

所有 SBE 場景都應該能在本地 Mock API 環境中執行:

1. 確認 Mock Handler 支援

檢查 src/mocks/handlers/ 是否有對應的 API endpoint。

2. 準備測試數據

src/mocks/data/seeds.ts 中添加必要的種子數據。

3. 執行測試

npm run dev  # 啟動 Mock API
# 在瀏覽器 Console 或 Postman 中測試 API

Three Amigos 協作

SBE 應由三方協作完成:

  1. 產品經理

    • 提供業務場景與預期行為
    • 確認範例數據的真實性
  2. 開發人員

    • 定義 API 請求/響應格式
    • 說明數據庫變更細節
  3. 測試人員

    • 設計邊界條件測試
    • 撰寫自動化測試代碼

審查檢查清單

提交 SBE 文檔前,請確認:

  • Given 包含完整的初始狀態(使用 JSON 格式)
  • When 提供完整的 HTTP 請求範例
  • Then 包含響應範例、數據庫變更、副作用
  • 至少包含 2 個錯誤場景
  • 提供可執行的自動化測試範例
  • 範例數據真實且有意義(非 foo/bar)
  • 所有 JSON 格式正確且完整
  • 與 Mock API 一致(可在本地驗證)
  • Markdown 格式正確

參考資源


最後更新: 2025-10-31