แนวคิดหลักคือ "Design Once, Tag by Level" — ออกแบบ Test Case ครั้งเดียว แต่ติด tag ว่า TC นั้นควรรันที่ level ไหน
โครงสร้างของ Test Suite ที่แนะนำ
Test Suite ที่ดีประกอบด้วย 3 ชั้น:
Test Suite
├── Test Scenario (SC-xxx) ← "อยากทดสอบอะไร" — 1 scenario ต่อ 1 พฤติกรรม
│ └── Test Case (TC-xxx) ← "ทดสอบยังไง" — 1 TC ต่อ 1 เงื่อนไข/ชุดข้อมูล
│ └── Test Data (TD-xxx) ← "ใช้ข้อมูลอะไร" — แยก data ออกจาก stepsLevel Tag System — หัวใจของ Multi-Level Suite
แต่ละ TC ต้องติด Level tag เพื่อบอกว่า TC นั้นรันที่ระดับไหน:
| Level | รันที่ไหน | ใครรัน | Focus |
|---|---|---|---|
Unit | Function / Class | Dev | Logic อย่างเดียว, mock ทุกอย่าง |
Integration | หลาย component รวมกัน | Dev / QA | Service A → DB, Service A → B |
API | HTTP endpoint จริง | QA | Request/Response contract |
E2E-Manual | Browser + UI ทั้งระบบ | QA / Manual Tester | User flow ตั้งแต่ต้นจนจบ |
TC บาง TC สามารถติดหลาย level ได้ เพราะ logic เดียวกัน แต่ verify คนละมุม
Template มาตรฐาน — ใช้ได้กับทุก Level
═══════════════════════════════════════════════════════
TEST SCENARIO
═══════════════════════════════════════════════════════
SC-ID: SC-[FEATURE]-[SEQ]
Feature: [ชื่อ Feature]
Scenario: [อธิบาย 1 ประโยค — ทดสอบพฤติกรรมอะไร]
Precondition: [สถานะระบบก่อนเริ่ม]
Expected: [ผลลัพธ์ที่ควรได้]
Priority: High / Medium / Low
Type: Functional | Boundary | Negative | Security | State
───────────────────────────────────────────────────────
TEST CASE (ลูกของ SC นี้)
───────────────────────────────────────────────────────
TC-ID: TC-[FEATURE]-[SEQ]
Title: [อธิบาย 1 ประโยค — ทดสอบเงื่อนไขอะไร]
Parent SC: SC-[FEATURE]-[SEQ]
Level: [ ] Unit [ ] Integration [ ] API [ ] E2E-Manual
(ติ๊กได้มากกว่า 1 ถ้า TC นี้ verify ได้หลาย level)
Priority: P1 (blocker) | P2 (major) | P3 (minor)
Technique: EP | BVA | State Transition | Decision Table | Error Guessing
Preconditions:
- [Auth state ที่ต้องการ]
- [Seed data ที่ต้องมีก่อน]
- [Environment: local | dev | staging]
Steps:
1. [Action]
2. [Action]
3. [Action]
Expected Output:
Status: [HTTP status หรือ UI state]
Response: [Fields และ values ที่คาดหวัง]
Side Effects: [DB เปลี่ยนยังไง, event ถูกส่งไหม, email ถูกส่งไหม]
Test Data Ref: TD-[SEQ] ← ชี้ไปที่ Test Data แยกต่างหาก
Level-Specific Notes:
Unit: [Mock อะไรบ้าง, function ไหนที่ test]
Integration: [Component ไหนรวมกัน, DB จริงหรือ test DB]
API: [Endpoint, Headers, Auth token ที่ใช้]
E2E-Manual: [Browser, URL เริ่มต้น, ขั้นตอน UI]
═══════════════════════════════════════════════════════
TEST DATA
═══════════════════════════════════════════════════════
TD-ID: TD-[SEQ]
Used By: TC-[SEQ], TC-[SEQ] ← TC ที่ใช้ data ชุดนี้
Input:
[field]: [value] # [เหตุผล เช่น "min boundary = 3 chars"]
[field]: [value]
Expected State After:
[entity]: [state ที่คาดหวังหลัง action]ตัวอย่างจริง — Feature: User Login
Scenario
SC-ID: SC-LOGIN-001
Feature: User Login
Scenario: ผู้ใช้ที่มี account ถูกต้องสามารถ login และรับ token ได้
Precondition: มี user account ที่ active อยู่ในระบบ
Expected: ได้รับ access token และ redirect ไปหน้า dashboard
Priority: High
Type: FunctionalTest Cases ลูก — แต่ละ TC ติด Level ต่างกัน
TC-ID: TC-LOGIN-001
Title: Login ด้วย email/password ถูกต้อง — ได้รับ token
Parent: SC-LOGIN-001
Level: [x] Unit [x] API [x] E2E-Manual
Priority: P1
Technique: Happy Path
Steps:
1. ส่ง credentials ที่ถูกต้อง
2. ตรวจสอบ response
Expected Output:
Status: 200 OK
Response: { token: <non-empty string>, user: { id, email, role } }
Side Effects: last_login_at ถูก update ใน DB
Test Data Ref: TD-LOGIN-001
Level-Specific Notes:
Unit: Test authService.login() โดย mock UserRepository + JwtService
API: POST /api/v1/auth/login — ใช้ test DB, ไม่ต้อง mock
E2E-Manual: เปิด browser → /login → กรอก form → คลิก Submit → ตรวจ redirect
───────────────────────────────────────────────────────
TC-ID: TC-LOGIN-002
Title: Login ด้วย password ผิด — ได้รับ 401 และ error message
Parent: SC-LOGIN-001
Level: [x] Unit [x] API [x] E2E-Manual
Priority: P1
Technique: Error Guessing / Negative
Expected Output:
Status: 401 Unauthorized
Response: { error: "Invalid credentials" }
Side Effects: ไม่มี token ถูกออก, ไม่มี session ถูกสร้าง
Level-Specific Notes:
Unit: ตรวจสอบว่า authService throw UnauthorizedException
API: ตรวจสอบ status code + response body
E2E-Manual: ตรวจสอบว่า error message แสดงบน UI และ user ยังอยู่หน้า login
───────────────────────────────────────────────────────
TC-ID: TC-LOGIN-003
Title: Login ด้วย email ที่ไม่มีในระบบ
Parent: SC-LOGIN-001
Level: [ ] Unit [x] API [x] E2E-Manual
Priority: P2
Technique: EP (invalid partition)
Level-Specific Notes:
Unit: ไม่จำเป็น — ครอบคลุมโดย TC-002 แล้ว (logic เดิม)
API: ต้องตรวจสอบว่า error message ไม่เปิดเผยว่า "email ไม่มีในระบบ" (security)
E2E-Manual: ตรวจสอบ UX — message ที่แสดงบน UITest Data แยกออกมา
TD-ID: TD-LOGIN-001
Used By: TC-LOGIN-001
Input:
email: "[email protected]" # registered, active account
password: "ValidPass1!" # correct password
Expected State After:
users table: last_login_at = NOW() (within 5 sec)
sessions table: new session record created
───────────────────────────────────────────────────────
TD-ID: TD-LOGIN-002
Used By: TC-LOGIN-002, TC-LOGIN-003
Input (TC-002 - wrong password):
email: "[email protected]"
password: "WrongPass999!"
Input (TC-003 - unknown email):
email: "[email protected]"
password: "AnyPass1!"วิธีจัดระเบียบ Test Suite ทั้งหมด
แนะนำให้จัดแบบนี้ ไม่ว่าจะเก็บใน Excel, Notion, Jira, หรือ Markdown:
Test Suite
├── Feature: Authentication
│ ├── SC-AUTH-001: Register
│ │ ├── TC-AUTH-001 (Unit, API, E2E)
│ │ └── TC-AUTH-002 (API, E2E)
│ ├── SC-AUTH-002: Login
│ │ ├── TC-AUTH-003 (Unit, API, E2E)
│ │ └── TC-AUTH-004 (API, E2E)
│ └── SC-AUTH-003: Logout
│ └── TC-AUTH-005 (Integration, API, E2E)
│
├── Feature: Order Management
│ ├── SC-ORDER-001: Create Order
│ └── SC-ORDER-002: Cancel Order
│
└── Test Data Pool
├── TD-001 ~ TD-010: Auth data
└── TD-011 ~ TD-020: Order dataสรุป — สิ่งที่ทำให้ Test Suite ใช้ได้หลาย Level
| หลักการ | รายละเอียด |
|---|---|
| Level Tag บน TC | บอกชัดว่า TC นี้รันที่ level ไหน — ไม่ต้องเขียนซ้ำ |
| Level-Specific Notes | บอก mock strategy / endpoint / UI steps แยกตาม level |
| Test Data แยกอิสระ | TD ถูก reuse ข้ามหลาย TC และหลาย level ได้ |
| TC ติด Parent SC | trace กลับได้ว่า TC นี้มาจาก scenario ไหน |
| Steps เป็น business language | อ่านได้ทั้ง Dev (unit) และ Manual Tester (E2E) |