# Lab 4: Requirements Analysis และ Test Case Design

## 🎯 Lab Objectives (วัตถุประสงค์ของ Lab)

หลังจบ Lab นี้ นิสิตจะสามารถ:

1. **วิเคราะห์ (Analyze)** ข้อกำหนด (Requirements) สำหรับ Member Registration
2. **สร้าง (Create)** Requirements Traceability Matrix (RTM) ให้มีคุณภาพ
3. **ออกแบบและเขียน (Design & Write)** Test Cases ที่มีคุณภาพ (20+ test cases)
4. **ใช้งาน (Use)** Test Case Management Tools เช่น GitHub Issues & Projects
5. **สร้าง (Generate)** test data โดยใช้ @faker-js/faker library
6. **เข้าใจ (Understand)** ความแตกต่างระหว่าง Positive vs Negative test cases
7. **ติดตาม (Track)** ความครอบคลุมของการทดสอบ (test coverage) ด้วย RTM

---

## 📋 Pre-Lab Preparation

### 1. Install Required Tools

```bash
# Check Node.js version (should be 18+)
node --version

# Install faker-js
npm install --save-dev @faker-js/faker

# Verify installation
node -e "const {faker} = require('@faker-js/faker'); console.log(faker.person.fullName())"
```

### 2. Clone/Pull Latest Library System Code

**สำหรับระบบ PHP + Docker:**

```bash
# Navigate to Library-Management project
cd Library-Management

# Pull latest code (if already cloned)
git pull origin main

# Start Docker containers
docker-compose up -d

# Wait for services to start (10-15 seconds)
docker-compose ps

# Access the application
# - Main app: http://localhost:8080
# - phpMyAdmin: http://localhost:8081
```

**Verify Login:**

- Username: `admin` / Password: `admin123`
- or Username: `librarian` / Password: `lib123`

### 3. Create Lab Workspace

```bash
# Create directories for lab work
mkdir -p test-cases/member-management/{registration}
mkdir -p test-data
mkdir -p documentation

# Files we'll create today:
# - documentation/RTM.xlsx (or Google Sheet)
# - test-cases/member-management/registration/TC-001.md
# - test-cases/member-management/registration/TC-002.md
# - test-data/generator.js
```

---

## Part 1: Requirements Analysis

### Exercise 1.1: Review Requirements Document

**Requirements สำหรับ Member Registration:**

```
FR-001: Member Registration Function
The system shall provide a member registration function that allows librarians
to register new members into the system.

FR-002: Member Registration Input Fields
The registration form shall include:
- Member Code (required, unique, format: MEMXXXX)
- Full Name (required, 3-100 characters)
- Email (required, valid email format)
- Phone (required, valid phone format)
- Member Type (required, dropdown: student/teacher/public)

FR-003: Member Code Validation
- Must be unique (no duplicates allowed)
- Format: MEMXXXX (MEM followed by 4 digits)
- System should auto-generate suggestion

FR-004: Full Name Validation
- Must be between 3-100 characters
- Can contain letters, numbers, spaces, and hyphens
- Cannot be empty

FR-005: Email Validation
- Must be in valid email format (xxx@yyy.zzz)
- Must be unique (no duplicates allowed)
- Domain should be validated

FR-006: Phone Validation
- Required field
- Must be valid phone format (10-15 digits with optional +, -, spaces)
- No special characters except +, -, ()

FR-007: Member Type Selection
- Three options: Student, Teacher, Public
- Determines maximum borrowing limit:
  - Student: 2 books
  - Teacher: 3 books
  - Public: 2 books

FR-008: Registration Success Behavior
Upon successful registration:
- Display success message "Member registered successfully!"
- Add registration date automatically (current date)
- Redirect to members list page
- Display new member in members list

FR-009: Registration Error Handling
Display appropriate error messages for:
- Empty required fields
- Invalid field formats
- Duplicate member code/email
- Invalid phone format
- Server errors
```

### Exercise 1.2: Identify Testable Items

**Task:** จากข้อกำหนดข้างต้น ให้ระบุ testable items

**Template:**

| Requirement ID | Testable Item                      | Test Type      | Priority |
| -------------- | ---------------------------------- | -------------- | -------- |
| FR-002         | Full Name length: 3-100 characters | Boundary Value | High     |
| FR-003         | Member Code format: MEMXXXX        | Validation     | High     |
| ...            | ...                                | ...            | ...      |

**ให้นิสิตเติมให้ครบ (15+ items)**

<details>
<summary>💡 Hint: คลิกเพื่อดู example</summary>

| Requirement ID | Testable Item                           | Test Type      | Priority |
| -------------- | --------------------------------------- | -------------- | -------- |
| FR-002         | Full Name length: 3-100 characters      | Boundary Value | High     |
| FR-002         | Email format validation                 | Validation     | High     |
| FR-002         | Phone format validation                 | Validation     | High     |
| FR-003         | Member Code format: MEMXXXX             | Validation     | High     |
| FR-003         | Member Code uniqueness                  | Business Logic | High     |
| FR-004         | Full Name minimum 3 characters          | Boundary Value | High     |
| FR-004         | Full Name maximum 100 characters        | Boundary Value | High     |
| FR-004         | Full Name with special characters       | Validation     | Medium   |
| FR-005         | Email uniqueness                        | Business Logic | High     |
| FR-005         | Email format validation                 | Validation     | High     |
| FR-006         | Phone format 10-15 digits               | Validation     | High     |
| FR-006         | Phone with +, -, () allowed             | Validation     | Medium   |
| FR-007         | Member Type dropdown shows 3 options    | UI             | High     |
| FR-007         | Member Type selection affects max_books | Business Logic | High     |
| FR-008         | Success message displayed               | UI             | High     |
| FR-008         | Registration date auto-set              | Business Logic | High     |
| FR-008         | Redirect to members list                | Navigation     | High     |
| FR-008         | New member appears in list              | Database       | High     |
| FR-009         | Error message for empty fields          | Error Handling | High     |
| FR-009         | Error message for invalid format        | Error Handling | High     |
| FR-009         | Error message for duplicates            | Error Handling | High     |

</details>

---

## Part 2: Setup Test Case Management

### Exercise 2.1: Setup GitHub Issues Labels

**Task:** สร้าง labels สำหรับ test case management ใน GitHub

**ขั้นตอน:**

1. ไปที่ GitHub Repository
2. คลิก **Issues** tab
3. คลิก **Labels** (ด้านขวา)
4. คลิก **New label** ปุ่มสีเขียว

**สร้าง labels เหล่านี้:**

| Label                 | Color   | Description          |
| --------------------- | ------- | -------------------- |
| `test-case`           | #0075CA | For test case issues |
| `priority-high`       | #D73A4A | High priority        |
| `priority-medium`     | #FFA500 | Medium priority      |
| `priority-low`        | #FFEB3B | Low priority         |
| `status-pass`         | #28A745 | Test passed ✅       |
| `status-fail`         | #DC3545 | Test failed ❌       |
| `status-blocked`      | #6C757D | Test blocked 🚫      |
| `status-not-run`      | #FFC107 | Not executed yet ⏳  |
| `test-positive`       | #00FF00 | Positive test case   |
| `test-negative`       | #FF0000 | Negative test case   |
| `module-registration` | #FF6B9D | Member registration  |
| `bug`                 | #EE0701 | Defect found         |

**คำแนะนำ:**

- สร้างทีละ label
- ใส่สี hex code ตามตาราข้างบน
- Add description

---

### Exercise 2.2: Create GitHub Issue Template

**Task:** สร้าง template สำหรับ test case issues

**ขั้นตอน:**

1. ในเครื่องของคุณ สร้าง folder: `.github/ISSUE_TEMPLATE/`

```bash
# Windows
mkdir .github\ISSUE_TEMPLATE

# Mac/Linux
mkdir -p .github/ISSUE_TEMPLATE
```

2. สร้างไฟล์: `.github/ISSUE_TEMPLATE/test_case.md`

**เนื้อหา:**

````markdown
---
name: Test Case
about: Template for creating test cases
title: "[TEST] TC-XXX: "
labels: ["test-case", "status-not-run"]
assignees: ""
---

## Test Case Information

**Test Case ID:** TC-XXX  
**Module:** Member Management > Registration  
**Priority:** High / Medium / Low  
**Type:** Positive / Negative

## Description

[Brief description of what this test case verifies]

## Preconditions

- [ ] Precondition 1
- [ ] Precondition 2

## Test Data

```json
{
  "member_code": "MEMXXXX",
  "full_name": "Test Name",
  "email": "test@example.com",
  "phone": "081XXXXXXXX",
  "member_type": "student"
}
```

## Test Steps

| Step | Action | Expected Result |
| ---- | ------ | --------------- |
| 1    | ...    | ...             |
| 2    | ...    | ...             |

## Expected Results

- [ ] Result 1
- [ ] Result 2

## Actual Results

[To be filled during execution]

## Status

- [ ] Not Run
- [ ] Pass
- [ ] Fail
- [ ] Blocked

## Notes

[Any observations or defect references]

**Traceability:** FR-XXX, TC-YYY, #bug_id
````

3. **Push ไปยัง GitHub:**

```bash
git add .github/ISSUE_TEMPLATE/test_case.md
git commit -m "Add test case template"
git push origin main
```

---

### Exercise 2.3: Create Test Case Issues in GitHub

**Task:** สร้าง test case แรก (TC-001) ใน GitHub Issues

**ขั้นตอน:**

1. ไปที่ repository บน GitHub
2. คลิก **Issues** tab
3. คลิก **New Issue** ปุ่มสีเขียว
4. เลือก **Test Case** template (จากที่สร้างไป)
5. ใส่ข้อมูล:

```
Title: [TEST] TC-001: ลงทะเบียนสมาชิกใหม่สำเร็จด้วยข้อมูลที่ถูกต้องทั้งหมด

ข้อมูล Test Case:
- Test Case ID: TC-001
- โมดูล: การจัดการสมาชิก > ลงทะเบียน
- ความสำคัญ: สูง (High)
- ประเภท: Positive Test (ทดสอบเคสบวก)

วัตถุประสงค์:
ตรวจสอบว่าเจ้าหน้าที่ห้องสมุดสามารถลงทะเบียนสมาชิกใหม่ได้สำเร็จ
ด้วยข้อมูลที่ถูกต้องครบถ้วน (รหัสสมาชิก, ชื่อเต็ม, อีเมล, เบอร์โทร, ประเภทสมาชิก)

เงื่อนไขเบื้องต้น (Preconditions):
- [x] ระบบทำงานได้ปกติ
- [x] เข้าสู่ระบบในฐานะเจ้าหน้าที่ห้องสมุด
- [x] หน้าจอแสดงรายการสมาชิก
- [x] รหัส MEM0001 ยังไม่มีในระบบ

ข้อมูล Test (Test Data):
{
  "member_code": "MEM0001",
  "full_name": "นักเรียนจอห์น",
  "email": "john.student@example.com",
  "phone": "0812345678",
  "member_type": "student"
}

ขั้นตอนการทดสอบ (Test Steps):
| ขั้นที่ | การกระทำ | ผลลัพธ์ที่คาดหวัง |
|---|---|---|
| 1 | คลิก "เพิ่มสมาชิกใหม่" | โมดัลปรากฏขึ้น |
| 2 | ป้อนรหัส MEM0001 | ยอมรับได้ |
| 3 | ป้อนชื่อ "นักเรียนจอห์น" | ยอมรับได้ |
| 4 | ป้อนอีเมล john.student@example.com | ยอมรับได้ |
| 5 | ป้อนเบอร์โทร 0812345678 | ยอมรับได้ |
| 6 | เลือกประเภท "นักเรียน" | เลือกเสร็จสิ้น |
| 7 | คลิก "เพิ่มสมาชิก" | ฟอร์มส่งข้อมูลสำเร็จ |

ผลลัพธ์ที่คาดหวัง (Expected Results):
- [ ] โมดัลปิด
- [ ] ระบบเปลี่ยนไปหน้ารายการสมาชิก
- [ ] สมาชิกใหม่ปรากฏในรายการ
- [ ] วันที่ลงทะเบียนถูกตั้งค่าโดยอัตโนมัติ
- [ ] จำนวนหนังสือสูงสุด (max_books) = 2 เล่ม

สถานะ: ยังไม่ได้ทำการทดสอบ (Not Run)

การติดตามความสอดคล้อง (Traceability): FR-001, FR-002, FR-008
```

6. **Add Labels:**

   - `test-case`
   - `priority-high`
   - `test-positive`
   - `module-registration`
   - `status-not-run`

7. คลิก **Create Issue**

---

### Exercise 2.4: Create More Test Cases (TC-002 to TC-025)

**Task:** สร้าง test cases อื่นๆ ใน GitHub Issues

**วิธีเร็ว:**

1. จาก TC-001 issue → คลิก **...** → **Duplicate issue**
2. แก้ไข:
   - Title (TC-002, TC-003, etc.)
   - Test data
   - Expected results
   - Labels

**Test cases ที่ควรสร้าง:**

| ID     | Type     | Purpose                      |
| ------ | -------- | ---------------------------- |
| TC-001 | Positive | Valid registration (student) |
| TC-002 | Positive | Valid registration (teacher) |
| TC-003 | Positive | Min full name (3 chars)      |
| TC-004 | Negative | Empty member code            |
| TC-005 | Negative | Empty full name              |
| TC-006 | Negative | Empty email                  |
| TC-007 | Negative | Empty phone                  |
| TC-008 | Positive | Valid member code format     |
| TC-009 | Negative | Duplicate member code        |
| TC-010 | Negative | Invalid email (no @)         |
| TC-011 | Negative | Duplicate email              |
| TC-012 | Negative | Min length boundary          |
| TC-013 | Negative | Max length boundary          |
| TC-014 | Positive | Public member type           |
| TC-015 | Edge     | Special characters in name   |
| ...    | ...      | ...                          |
| TC-025 | Edge     | Boundary + special cases     |

---

### Exercise 2.5: Organize Issues with GitHub Projects (Optional)

**Task:** ใช้ GitHub Projects เพื่อจัดการ test cases ให้ง่ายต่อการติดตาม

#### Step 1: Create New Project & Set Up Table

1. ไปที่ GitHub Repository → คลิก **Projects** tab
2. คลิก **New project** → เลือก **Table** template
3. ตั้งชื่อ: `Lab 4 - Member Registration Testing`
4. ระดับ Visibility: Public → คลิก **Create project**

#### Step 2: Add 3 Custom Columns

คลิก **+ Add field** สร้าง columns:

| Name         | Type          | Options                                          |
| ------------ | ------------- | ------------------------------------------------ |
| **Priority** | Single select | High (🔴), Medium (🟡), Low (🟢)                 |
| **Type**     | Single select | Positive (✅), Negative (❌), Edge (🔷)          |
| **Status**   | Single select | Not Run (⏳), Pass (✅), Fail (❌), Blocked (🚫) |

#### Step 3: Add Test Case Issues & Track

1. สร้าง test cases ใน GitHub Issues (TC-001 ถึง TC-015)
2. เปิด issue แล่ะ **Add to project** → เลือก project
3. กรอก Priority, Type, Status สำหรับแต่ละ TC
4. ติดตาม progress: Drag-drop issues ไป Status columns

**ตัวอย่าง:**

```
TC-001: Pass (✅) | Priority: High | Type: Positive
TC-004: Not Run (⏳) | Priority: High | Type: Negative
```

**ประโยชน์:**

- ✅ เห็น test status ทั้งหมดในหน้าเดียว
- ✅ ติดตาม progress easily (drag-drop)
- ✅ สามารถ filter by Priority/Type

**วิธีที่ 1: Add from Issue (แนะนำ)**

1. เปิด issue TC-001 ที่สร้างไป
2. ในด้านขวา ดูหมวด **Projects**
3. คลิก **Add to project**
4. เลือก "Lab 4 - Member Registration Testing"
5. Issue จะปรากฏใน project table

**วิธีที่ 2: Add from Project**

1. ไปที่ project board
2. คลิก **Add item** (หรือ **+ Add** ด้านล่าง)
3. ค้นหา issue TC-001
4. คลิกเลือก

#### Step 5: Fill in Project Details for Each Test Case

**สำหรับแต่ละ TC issues:**

1. ไปที่ project table
2. คลิก row ของ TC-001
3. กรอก columns:

   - **Priority:** High
   - **Type:** Positive
   - **Requirement:** FR-001, FR-002, FR-008
   - **Execution Status:** ⏳ Not Run

4. ทำซ้ำสำหรับ TC-002, TC-003, ... TC-025

**ตัวอย่าง:**

```
TC-001: Register Student
┌─────────────────────────────────────────────────────┐
│ Priority:           [High]                          │
│ Type:               [Positive]                      │
│ Requirement:        [FR-001, FR-002, FR-008]       │
│ Execution Status:   [⏳ Not Run]                    │
└─────────────────────────────────────────────────────┘

TC-002: Register Teacher
┌─────────────────────────────────────────────────────┐
│ Priority:           [High]                          │
│ Type:               [Positive]                      │
│ Requirement:        [FR-001, FR-002, FR-007]       │
│ Execution Status:   [⏳ Not Run]                    │
└─────────────────────────────────────────────────────┘

TC-004: Empty Member Code
┌─────────────────────────────────────────────────────┐
│ Priority:           [High]                          │
│ Type:               [Negative]                      │
│ Requirement:        [FR-002, FR-009]                │
│ Execution Status:   [⏳ Not Run]                    │
└─────────────────────────────────────────────────────┘
```

#### Step 6: Track Progress During Execution

**เมื่อเริ่มทำ test case:**

1. เปิด project board
2. สามารถ drag-drop issues ไปที่ Status columns:

   ```
   ⏳ Not Run → ✅ Pass  (เมื่อผ่าน)
   ⏳ Not Run → ❌ Fail  (เมื่อล้มเหลว)
   ⏳ Not Run → 🚫 Blocked (เมื่อติดขัด)
   ```

3. หรือ update ผ่าน table cells

**ตัวอย่าง Progress:**

```
BEFORE:
┌────────┬──────────────────┐
│ Title  │ Execution Status │
├────────┼──────────────────┤
│ TC-001 │ ⏳ Not Run       │
│ TC-002 │ ⏳ Not Run       │
│ TC-003 │ ⏳ Not Run       │
└────────┴──────────────────┘

AFTER:
┌────────┬──────────────────┐
│ Title  │ Execution Status │
├────────┼──────────────────┤
│ TC-001 │ ✅ Pass         │
│ TC-002 │ ✅ Pass         │
│ TC-003 │ ❌ Fail         │
└────────┴──────────────────┘
```

#### Step 7: View Project Insights (Optional)

**GitHub Projects มี insights ของ:**

- จำนวน issues ใน status แต่ละตัว
- Burndown chart (progress tracking)
- Priority distribution

**วิธีเข้า:**

1. ไปที่ project board
2. คลิก **Insights** tab
3. ดูสถิติ test cases

#### ประโยชน์ของ GitHub Projects:

✅ **มองภาพรวมได้ง่าย** - เห็น test status ทั้งหมด  
✅ **ติดตาม progress** - เห็นว่าทำเสร็จกี่ % แล้ว  
✅ **จัด prioritize** - เห็นว่า high priority cases ไหน  
✅ **Collaboration** - Team ทุกคนเห็น status เดียวกัน  
✅ **Automated updates** - ปรับ issue label → project updated

#### Troubleshooting:

**ปัญหา: Project ไม่เห็นใน GitHub Repository**

- สาเหตุ: Repository เป็น private
- วิธีแก้: ให้ instructor access หรือเปลี่ยน public

**ปัญหา: Issues ไม่เห็นใน project**

- สาเหตุ: ยังไม่ได้ add issues ไปยัง project
- วิธีแก้: ตามขั้นตอน Step 4 อีกครั้ง

**ปัญหา: ไม่เห็น custom columns**

- สาเหตุ: ใช้ GitHub free plan ที่ไม่ support (ก่อน 2022)
- วิธีแก้: Upgrade plan หรือใช้ Google Sheets แทน

---

## Part 3: Create Requirements Traceability Matrix

### Exercise 3.1: Create RTM Structure

**Option A: Using Google Sheets (แนะนำ)**

1. Create new Google Sheet: "Library System - Member Registration RTM"
2. Create tabs:
   - "Member Registration RTM"
   - "Summary Dashboard"

**Option B: Using Excel**

Create file: `documentation/Member_Registration_RTM.xlsx`

### Exercise 3.2: Build Member Registration RTM

**Member Registration RTM Template:**

Create sheet with columns:

| Req ID | Requirement Description | Positive Test Cases | Negative Test Cases | Edge Cases | Total Coverage | Status | Defects |
| ------ | ----------------------- | ------------------- | ------------------- | ---------- | -------------- | ------ | ------- |
| ...    | ...                     | ...                 | ...                 | ...        | ...            | ...    | ...     |

**Step-by-step:**

```

Column A: Req ID (FR-001, FR-002, etc.)
Column B: Requirement Description (short summary)
Column C: Positive Test Cases (TC IDs)
Column D: Negative Test Cases (TC IDs)
Column E: Edge Cases (TC IDs)
Column F: Total Coverage (formula: count all TCs)
Column G: Execution Status (Not Run/Pass/Fail/Blocked)
Column H: Defects (Bug IDs if any)

```

**Example Rows:**

| Req ID | Requirement Description    | Positive TCs   | Negative TCs           | Edge TCs | Total | Status  | Defects |
| ------ | -------------------------- | -------------- | ---------------------- | -------- | ----- | ------- | ------- |
| FR-001 | Member can register        | TC-001, TC-002 | TC-004, TC-005         | TC-015   | 5     | Not Run | -       |
| FR-002 | Registration fields        | TC-001, TC-002 | TC-006, TC-007         | -        | 4     | Not Run | -       |
| FR-003 | Member Code format MEMXXXX | TC-008         | TC-009, TC-010         | TC-016   | 4     | Not Run | -       |
| FR-004 | Full Name 3-100 chars      | TC-003, TC-011 | TC-012, TC-013         | TC-017   | 5     | Not Run | -       |
| FR-005 | Email validation           | TC-001         | TC-014, TC-018         | TC-019   | 4     | Not Run | -       |
| FR-006 | Phone validation           | TC-001         | TC-020, TC-021         | TC-022   | 4     | Not Run | -       |
| FR-007 | Member Type selection      | TC-002         | TC-023                 | -        | 2     | Not Run | -       |
| FR-008 | Registration success       | TC-001, TC-002 | -                      | -        | 2     | Not Run | -       |
| FR-009 | Error handling             | -              | TC-004, TC-024, TC-025 | -        | 3     | Not Run | -       |

**🎯 Task:** สร้าง RTM ครบทุก requirement (FR-001 ถึง FR-009)

### Exercise 3.3: Add Summary Metrics

**Create Summary Dashboard tab:**

```

╔══════════════════════════════════════════════╗
║ MEMBER REGISTRATION TEST COVERAGE            ║
╠══════════════════════════════════════════════╣
║ Total Requirements: 9                        ║
║ Total Test Cases: 25+                        ║
║ Positive Test Cases: 8 (32%)                 ║
║ Negative Test Cases: 14 (56%)                ║
║ Edge Cases: 3+ (12%)                         ║
║                                              ║
║ Requirements Coverage: 100%                  ║
║ Test Cases Executed: 0/25+ (0%)              ║
║ Test Cases Passed: 0/25+ (0%)                ║
║ Test Cases Failed: 0/25+ (0%)                ║
║ Defects Found: 0                             ║
║                                              ║
║ Status: Ready for Execution                  ║
╚══════════════════════════════════════════════╝

```

**Use formulas:**

```excel
Total Requirements:     =COUNTA('Member Registration RTM'!A2:A100)
Total Test Cases:       =SUM('Member Registration RTM'!F2:F100)
Positive TCs:          =COUNTIF('Member Registration RTM'!C2:C100,"<>")
Negative TCs:          =COUNTIF('Member Registration RTM'!D2:D100,"<>")
Requirements Coverage:  =COUNTA('Member Registration RTM'!A2:A100)/9*100&"%"
```

### Exercise 3.4: Backward Traceability Check

**Task:** ตรวจสอบว่าทุก Test Case link กลับไปยัง Requirement

Create validation sheet:

| Test Case ID | Module       | Linked Requirements            | Valid? |
| ------------ | ------------ | ------------------------------ | ------ |
| TC-001       | Registration | FR-001, FR-002, FR-004, FR-005 | ✅     |
| TC-002       | Registration | FR-002                         | ✅     |
| TC-003       | Registration | FR-002                         | ✅     |
| TC-004       | Registration | FR-002                         | ✅     |
| ...          | ...          | ...                            | ...    |

**Validation Rules:**

- ✅ Every test case MUST link to at least one requirement
- ✅ Every requirement MUST have at least one test case
- ❌ Orphan test cases (no requirement) = Red flag
- ❌ Untested requirements = Missing coverage

---

## Part 4: Write Test Cases

### Exercise 4.1: Create Test Case Files

**Directory structure:**

```
test-cases/
└── member-management/
    └── registration/
        ├── TC-001.md (Positive - Valid registration)
        ├── TC-002.md (Positive - Teacher type)
        ├── TC-003.md (Positive - Min full name)
        ├── TC-004.md (Negative - Empty member code)
        ├── TC-005.md (Negative - Empty full name)
        ├── TC-006.md (Negative - Empty email)
        ├── TC-007.md (Negative - Empty phone)
        ├── TC-008.md (Positive - Valid member code)
        ├── TC-009.md (Positive - Member code format)
        ├── TC-010.md (Negative - Duplicate member code)
        ├── TC-011.md (Negative - Invalid format)
        ├── TC-012.md (Negative - Special chars)
        ├── TC-013.md (Positive - Valid email)
        ├── TC-014.md (Negative - Min length)
        ├── TC-015.md (Negative - Max length)
        ├── TC-016.md (Negative - No @ symbol)
        ├── TC-017.md (Negative - No domain)
        ├── TC-018.md (Negative - Duplicate email)
        ├── TC-019.md (Positive - Valid phone)
        └── TC-020.md (Negative - Invalid phone)
```

### Exercise 4.2: Write Positive Test Cases

**Template:** `TC-001_Valid_Registration.md`

````markdown
# TC-001: Successful Registration with All Valid Data

## Test Case Information

- **ID:** TC-001
- **Module:** User Management > Registration
- **Priority:** High
- **Type:** Positive Test
- **Requirement:** FR-001, FR-002, FR-004, FR-005, FR-006

## Objective

Verify that a new user can successfully register with all valid data
meeting all validation requirements.

## Preconditions

- System is running at http://localhost:3000
- Registration page is accessible
- Database is in clean state (or test username doesn't exist)
- SMTP service is running (for email verification)

## Test Data

```json
{
  "username": "john_doe_2024",
  "email": "john.doe@example.com",
  "password": "SecurePass123!",
  "confirmPassword": "SecurePass123!"
}
```

## Test Steps

| Step | Action                                               | Expected Result                                            | ✓   |
| ---- | ---------------------------------------------------- | ---------------------------------------------------------- | --- |
| 1    | Open browser and navigate to `http://localhost:3000` | Homepage loads successfully                                | ☐   |
| 2    | Click "Sign Up" or "Register" button                 | Registration form is displayed                             | ☐   |
| 3    | Verify form fields are present                       | Username, Email, Password, Confirm Password fields visible | ☐   |
| 4    | Enter `john_doe_2024` in Username field              | Text appears in field, no error                            | ☐   |
| 5    | Enter `john.doe@example.com` in Email field          | Text appears in field, no error                            | ☐   |
| 6    | Enter `SecurePass123!` in Password field             | Text is masked (\*\*\*\*), no error                        | ☐   |
| 7    | Enter `SecurePass123!` in Confirm Password field     | Text is masked (\*\*\*\*), passwords match indication      | ☐   |
| 8    | Click "Register" or "Sign Up" button                 | Loading indicator appears                                  | ☐   |
| 9    | Wait for response                                    | Success message displayed                                  | ☐   |

## Expected Results

### Primary Results (MUST verify)

1. ✅ Success message displayed: "Registration successful!" or similar
2. ✅ User is automatically logged in (session created)
3. ✅ Page redirects to dashboard/home page
4. ✅ Redirect happens within 2 seconds

### Secondary Results (SHOULD verify)

5. ✅ User profile shows correct username and email
6. ✅ Database contains new user record
7. ✅ Password is hashed (not plain text) in database
8. ✅ User has default role/permissions
9. ✅ Welcome email is sent (check email logs/queue)

### Database Verification

```sql
SELECT * FROM users WHERE username = 'john_doe_2024';
-- Expected: 1 row with hashed password
```

### API Verification (if applicable)

```bash
curl -X POST http://localhost:3000/api/users/register \
  -H "Content-Type: application/json" \
  -d '{"username":"john_doe_2024","email":"john.doe@example.com","password":"SecurePass123!"}'

# Expected: 201 Created
# Response: {"success": true, "userId": 123, "message": "Registration successful"}
```

## Actual Results

[To be filled during execution]

**Execution Date:** \***\*\_\_\*\***  
**Tester:** \***\*\_\_\*\***  
**Environment:** Development / Staging / Production  
**Build/Version:** v1.0.0

**Result:** ☐ Pass ☐ Fail ☐ Blocked

**Notes:**
[Any observations, issues, or comments]

## Postconditions

- New user exists in database
- User can login with registered credentials
- Test data should be cleaned up after test (optional for dev)

## Related Test Cases

- TC-002: Minimum username length
- TC-003: Maximum username length
- TC-010: Duplicate username

## Defects

[Reference any defects found during execution]

- Example: BUG-042 - Email not being sent
````

### Exercise 4.3: Write Negative Test Cases

**Task:** เขียน negative test cases อย่างน้อย 10 test cases

**ตัวอย่างเทมเพลต:** `TC-004_Empty_Member_Code.md`

````markdown
# TC-004: ลงทะเบียนด้วยรหัสสมาชิกเป็นค่าว่าง (Empty Member Code)

## ข้อมูล Test Case

- **ID:** TC-004
- **โมดูล:** การจัดการสมาชิก > ลงทะเบียน
- **ความสำคัญ:** สูง (High)
- **ประเภท:** Negative Test (ทดสอบเคสลบ)
- **ข้อกำหนด:** FR-002, FR-009

## วัตถุประสงค์ (Objective)

ตรวจสอบว่าระบบสามารถตรวจสอบ (validate) และปฏิเสธ
การลงทะเบียนได้อย่างถูกต้องเมื่อช่องรหัสสมาชิกเว้นว่าง

## เงื่อนไขเบื้องต้น (Preconditions)

- ระบบทำงานที่ http://localhost:3000
- หน้าการลงทะเบียนเข้าถึงได้

## ข้อมูล Test Data

```json
{
  "member_code": "",
  "full_name": "นักเรียนทดสอบ",
  "email": "test@example.com",
  "phone": "0812345678",
  "member_type": "student"
}
```

## ขั้นตอนการทดสอบ (Test Steps)

| ขั้นที่ | การกระทำ                                               | ผลลัพธ์ที่คาดหวัง          | ✓   |
| ------- | ------------------------------------------------------ | -------------------------- | --- |
| 1       | ไปที่หน้าลงทะเบียน                                     | ฟอร์มแสดงขึ้นมา            | ☐   |
| 2       | ไม่ป้อนอะไรในช่องรหัสสมาชิก                            | ช่องเหลือว่าง              | ☐   |
| 3       | ป้อนข้อมูลอื่นๆ ให้ครบ (ชื่อ, อีเมล, เบอร์โทร, ประเภท) | ข้อมูลถูกยอมรับ            | ☐   |
| 4       | คลิกปุ่ม "เพิ่มสมาชิก"                                 | ฟอร์มไม่ส่งข้อมูล          | ☐   |
| 5       | สังเกตช่องรหัสสมาชิก                                   | ข้อความแสดงข้อผิดพลาดปรากฏ | ☐   |
| 5       | Click "Register" button                                | Form does not submit       | ☐   |
| 6       | Observe username field                                 | Error message appears      | ☐   |

## Expected Results

### Primary Results

1. ✅ Error message displayed near Username field
2. ✅ Error message text: "Username is required" or similar
3. ✅ Form is NOT submitted
4. ✅ Page does NOT redirect
5. ✅ No user record created in database

### Error Message Validation

- Message is clearly visible (red text or similar)
- Message appears immediately after clicking Register
- Message persists until username is entered
- Message is descriptive and actionable

### UI State Verification

- Username field highlighted/outlined in red
- Register button remains enabled (allows retry)
- Other fields retain their values (not cleared)
- No loading indicator shown

## Actual Results

[To be filled during execution]

## Expected Behavior Variations

**ตรวจสอบฝั่งไคลเอนต์ (Client-side validation) - ที่ดีที่สุด:**

- ข้อผิดพลาดปรากฏทันทีหลังออกจากช่อง
- ไม่มีการส่งข้อมูลไปยังเซิร์ฟเวอร์
- ได้รับข้อมูลตอบกลับจากผู้ใช้อย่างรวดเร็ว

**ตรวจสอบฝั่งเซิร์ฟเวอร์ (Server-side validation):**

- ส่งข้อมูลไปยังเซิร์ฟเวอร์
- เซิร์ฟเวอร์ส่งกลับข้อผิดพลาด 400 Bad Request
- ข้อมูลข้อผิดพลาดแสดงจากการตอบสนอง

**ทั้งสองวิธี (Best practice):**

- ตรวจสอบฝั่งไคลเอนต์เพื่อข้อมูลตอบกลับอย่างรวดเร็ว
- ตรวจสอบฝั่งเซิร์ฟเวอร์เพื่อความปลอดภัย
- ข้อมูลข้อผิดพลาดสอดคล้องกัน

## Test Cases ที่เกี่ยวข้อง (Related Test Cases)

- TC-005: ชื่อเต็มเป็นค่าว่าง
- TC-006: อีเมลเป็นค่าว่าง
- TC-007: เบอร์โทรเป็นค่าว่าง

## หมายเหตุ (Notes)

นี่คือการทดสอบการตรวจสอบที่สำคัญ ระบบจะต้องไม่อนุญาต
ให้ลงทะเบียนด้วยข้อมูลที่จำเป็นเว้นว่าง
````

**🎯 Assignment:** เขียน test cases ต่อไปนี้ (เลือก 15 test cases จาก 22 ข้อด้านล่าง)

**จำเป็น (ต้องเขียน):**

1. TC-001: Valid registration (Student) ← เดี่ยว
2. TC-004: Empty member code ← เดี่ยว
3. TC-005 ถึง TC-015: เลือก 11 TC จากรายชื่อด้านล่าง

**ตัวอย่าง TC ที่สามารถเลือก (เลือก 11 จาก 17 นี้):**

| No.    | Test Case                            | ความสำคัญ   |
| ------ | ------------------------------------ | ----------- |
| TC-005 | Empty full name                      | 🔴 High     |
| TC-006 | Empty email                          | 🔴 High     |
| TC-007 | Empty phone                          | 🔴 High     |
| TC-008 | Invalid email format (no @)          | 🔴 High     |
| TC-009 | Duplicate member code                | 🔴 High     |
| TC-010 | Duplicate email                      | 🔴 High     |
| TC-011 | Full name too short (< 3 chars)      | 🟡 Medium   |
| TC-012 | Full name too long (> 100 chars)     | 🟡 Medium   |
| TC-013 | Phone invalid format                 | 🟡 Medium   |
| TC-014 | Valid registration (Teacher)         | 🔴 High     |
| TC-015 | Valid registration (Public)          | 🟡 Medium   |
| TC-016 | Member code invalid format           | 🟡 Medium   |
| TC-017 | Special characters in name           | 🟡 Medium   |
| TC-018 | Email domain invalid                 | 🟡 Medium   |
| TC-019 | Phone with special chars allowed     | 🟡 Medium   |
| TC-020 | SQL Injection in member code (Bonus) | 🔷 Security |
| TC-021 | XSS attempt in name (Bonus)          | 🔷 Security |

**💡 ตัวอย่างการเลือก:**

- Option A (ง่าย): เลือก High ทั้งหมด (TC-005, 006, 007, 008, 009, 010, 014) = 7 TC + เพิ่ม Medium 4 TC = 11 TC รวม 15
- Option B (ปกติ): เลือก High 7 + Medium 4 = 11 TC รวม 15
- Option C (เก่งมาก): เลือก High 7 + Medium 4 + Security 2 (TC-020, 021 bonus) = 13 TC

**ส่งให้เสร็จภายใน:** [ให้นิสิตวางแผนเอง]

---

**Bonus (Security Testing):**

- TC-020: SQL Injection attempt in member code
- TC-021: XSS attempt in name
- TC-022: Very long input (buffer overflow attempt)

---

## Part 5: Test Data Generation with Faker

### Exercise 5.1: Setup Faker

```bash
# Install faker
npm install --save-dev @faker-js/faker

# Create test data directory
mkdir test-data
cd test-data
```

### Exercise 5.2: Create Test Data Generator

**Create file:** `test-data/userDataGenerator.js`

```javascript
/**
 * Test Data Generator for User Registration Testing
 * Uses faker-js to generate realistic test data
 */

const { faker } = require("@faker-js/faker");

/**
 * Generate a single valid test user
 */
function generateValidUser() {
  const firstName = faker.person.firstName();
  const lastName = faker.person.lastName();

  return {
    username: faker.internet.userName({ firstName, lastName }),
    email: faker.internet.email({ firstName, lastName }),
    password: generateValidPassword(),
    firstName: firstName,
    lastName: lastName,
    phone: faker.phone.number(),
    dateOfBirth: faker.date.birthdate({ min: 18, max: 80, mode: "age" }),
    address: {
      street: faker.location.streetAddress(),
      city: faker.location.city(),
      zipCode: faker.location.zipCode(),
      country: faker.location.country(),
    },
  };
}

/**
 * Generate valid password (meets all requirements)
 */
function generateValidPassword() {
  // Ensure password meets all requirements:
  // - At least 8 characters
  // - Contains uppercase, lowercase, number
  const upper = faker.string.alpha({ length: 2, casing: "upper" });
  const lower = faker.string.alpha({ length: 2, casing: "lower" });
  const numbers = faker.string.numeric(2);
  const special = faker.helpers.arrayElement(["!", "@", "#", "$", "%"]);

  // Shuffle to make it look natural
  const chars = (upper + lower + numbers + special).split("");
  return faker.helpers.shuffle(chars).join("") + faker.string.alphanumeric(3); // Add more chars to ensure length
}

/**
 * Generate multiple valid users
 */
function generateValidUsers(count = 10) {
  return Array.from({ length: count }, () => generateValidUser());
}

/**
 * Generate invalid usernames for negative testing
 */
function generateInvalidUsernames() {
  return {
    tooShort: faker.string.alpha(3), // 3 chars (min is 4)
    tooLong: faker.string.alpha(21), // 21 chars (max is 20)
    withSpecialChars: `${faker.internet.userName()}@!`, // Contains @!
    startsWithUnderscore: `_${faker.internet.userName()}`,
    endsWithUnderscore: `${faker.internet.userName()}_`,
    consecutiveUnderscores: faker.internet.userName().replace(/_/g, "__"),
    onlyNumbers: faker.string.numeric(10),
    withSpaces: faker.person.fullName(), // Contains space
    empty: "",
    sqlInjection: "admin'--",
    xssAttempt: "<script>alert('xss')</script>",
  };
}

/**
 * Generate invalid emails for negative testing
 */
function generateInvalidEmails() {
  return {
    missingAt: "invalidemail.com",
    missingDomain: "user@",
    missingLocal: "@domain.com",
    multipleAt: "user@@domain.com",
    spacesInEmail: "user name@domain.com",
    invalidDomain: "user@domain",
    specialCharsLocal: "user!#$%@domain.com",
    tooLong: faker.string.alpha(100) + "@domain.com",
    empty: "",
  };
}

/**
 * Generate invalid passwords for negative testing
 */
function generateInvalidPasswords() {
  return {
    tooShort: faker.string.alphanumeric(5), // Less than 8
    noUppercase: "password123", // All lowercase + numbers
    noLowercase: "PASSWORD123", // All uppercase + numbers
    noNumbers: "PasswordOnly", // Only letters
    onlyNumbers: "12345678", // Only numbers
    empty: "",
    common: "Password123", // Too common
    repeating: "aaaaaaaa", // Repeating chars
  };
}

/**
 * Generate boundary test data for username
 */
function generateUsernameBoundaries() {
  return {
    minLength: faker.string.alpha(4), // Exactly 4 (minimum valid)
    minMinus1: faker.string.alpha(3), // 3 (just below minimum)
    maxLength: faker.string.alpha(20), // Exactly 20 (maximum valid)
    maxPlus1: faker.string.alpha(21), // 21 (just above maximum)
    typical: faker.internet.userName(), // Typical length (8-12)
  };
}

/**
 * Generate complete test dataset for test cases
 */
function generateTestDataset() {
  return {
    validUsers: generateValidUsers(5),
    invalidUsernames: generateInvalidUsernames(),
    invalidEmails: generateInvalidEmails(),
    invalidPasswords: generateInvalidPasswords(),
    boundaryUsernames: generateUsernameBoundaries(),
  };
}

/**
 * Generate test data for specific test case
 */
function generateForTestCase(testCaseId) {
  const generators = {
    "TC-001": () => generateValidUser(),
    "TC-002": () => ({
      ...generateValidUser(),
      username: faker.string.alpha(4),
    }),
    "TC-003": () => ({
      ...generateValidUser(),
      username: faker.string.alpha(20),
    }),
    "TC-004": () => ({ ...generateValidUser(), username: "" }),
    "TC-005": () => ({
      ...generateValidUser(),
      username: faker.string.alpha(3),
    }),
    "TC-006": () => ({
      ...generateValidUser(),
      username: faker.string.alpha(21),
    }),
    "TC-007": () => ({
      ...generateValidUser(),
      username: `${faker.internet.userName()}@!`,
    }),
    // Add more mappings as needed
  };

  const generator = generators[testCaseId];
  return generator ? generator() : generateValidUser();
}

/**
 * Export data to JSON file for use in tests
 */
function exportToJson(filename = "test-data.json") {
  const fs = require("fs");
  const data = generateTestDataset();

  fs.writeFileSync(filename, JSON.stringify(data, null, 2), "utf-8");

  console.log(`✅ Test data exported to ${filename}`);
  console.log(`📊 Generated ${data.validUsers.length} valid users`);
}

// Export functions
module.exports = {
  generateValidUser,
  generateValidUsers,
  generateValidPassword,
  generateInvalidUsernames,
  generateInvalidEmails,
  generateInvalidPasswords,
  generateUsernameBoundaries,
  generateTestDataset,
  generateForTestCase,
  exportToJson,
};

// CLI usage
if (require.main === module) {
  // Generate and display sample data
  console.log("🎲 Generating Sample Test Data...\n");

  console.log("✅ Valid User:");
  console.log(JSON.stringify(generateValidUser(), null, 2));

  console.log("\n❌ Invalid Usernames:");
  console.log(JSON.stringify(generateInvalidUsernames(), null, 2));

  console.log("\n📊 Boundary Values:");
  console.log(JSON.stringify(generateUsernameBoundaries(), null, 2));

  // Export to file
  console.log("\n💾 Exporting full dataset...");
  exportToJson("test-data.json");
}
```

### Exercise 5.3: Use Faker in Test Cases

**Create:** `test-data/demo-usage.js`

```javascript
const {
  generateValidUser,
  generateInvalidUsernames,
  generateForTestCase,
} = require("./userDataGenerator");

// Example 1: Generate data for positive test
console.log("=== TC-001: Valid Registration ===");
const validUser = generateValidUser();
console.log(`Username: ${validUser.username}`);
console.log(`Email: ${validUser.email}`);
console.log(`Password: ${validUser.password}`);

// Example 2: Generate data for negative tests
console.log("\n=== TC-004 to TC-010: Invalid Usernames ===");
const invalidUsernames = generateInvalidUsernames();
console.log("Too short:", invalidUsernames.tooShort);
console.log("Too long:", invalidUsernames.tooLong);
console.log("Special chars:", invalidUsernames.withSpecialChars);
console.log("SQL Injection:", invalidUsernames.sqlInjection);

// Example 3: Generate specific test case data
console.log("\n=== Generate for Specific Test Case ===");
const tc001Data = generateForTestCase("TC-001");
console.log("TC-001 Data:", tc001Data);

// Example 4: Generate bulk test data
console.log("\n=== Generate 10 Users for Load Testing ===");
const { generateValidUsers } = require("./userDataGenerator");
const users = generateValidUsers(10);
users.forEach((user, index) => {
  console.log(`User ${index + 1}: ${user.username} (${user.email})`);
});

// Example 5: Export to file for manual testing
console.log("\n=== Export Test Data ===");
const { exportToJson } = require("./userDataGenerator");
exportToJson("registration-test-data.json");
console.log("✅ Data exported successfully!");
```

**Run it:**

```bash
node userDataGenerator.js
node demo-usage.js
```

### Exercise 5.4: Integration with Test Cases

**Task:** ใช้ Faker.js เพื่อสร้าง test data สำหรับ test cases และปรับปรุง TC ให้ใช้ generated data

#### Step 1: Generate Test Data Using Bash Command

**Run the data generator:**

```bash
# Generate single valid user
node -e "const {generateValidUser} = require('./userDataGenerator'); console.log(JSON.stringify(generateValidUser(), null, 2))"
```

**Expected Output:**

```json
{
  "username": "john_doe_2024",
  "email": "john.doe@example.com",
  "password": "SecurePass123!",
  "firstName": "John",
  "lastName": "Doe",
  "phone": "0812345678",
  "dateOfBirth": "1990-05-15",
  "address": {
    "street": "123 Main Street",
    "city": "Bangkok",
    "zipCode": "10110",
    "country": "Thailand"
  }
}
```

#### Step 2: Update Test Case File with Generated Data

**Original TC-001.md:**

```markdown
# TC-001: Valid Registration

## Test Data

{
"username": "testuser123",
"email": "test@example.com",
...
}
```

**Updated TC-001.md (with Faker):**

````markdown
# TC-001: Valid Registration (Generated Data)

## Test Data Generation Command

```bash
node -e "const {generateValidUser} = require('./userDataGenerator'); const user = generateValidUser(); console.log(JSON.stringify(user, null, 2))"
```
````

## Test Data (Auto-Generated from Faker)

```json
{
  "username": "john_doe_2024",  // <- Generated by Faker
  "email": "john.doe@example.com",
  "password": "SecurePass123!",
  ...
}
```

## How to Use This Data

1. Copy the JSON output
2. Paste into registration form
3. Record actual results

````

#### Step 3: Repeat for Multiple Test Cases

**Generate data for different member types:**

```bash
# For TC-002: Teacher registration
node -e "const {generateValidUser} = require('./test-data/userDataGenerator'); const user = {memberType: 'teacher', ...generateValidUser()}; console.log(JSON.stringify(user, null, 2))"

# For TC-003: Public member registration
node -e "const {generateValidUser} = require('./test-data/userDataGenerator'); const user = {memberType: 'public', ...generateValidUser()}; console.log(JSON.stringify(user, null, 2))"
````

#### Step 4: Generate Invalid Data for Negative Tests

**For TC-004 (Empty member code):**

```bash
node -e "const {generateValidUser} = require('./test-data/userDataGenerator'); const invalid = {...generateValidUser(), username: ''}; console.log(JSON.stringify(invalid, null, 2))"
```

**For TC-005 (Invalid email - no @):**

```bash
node -e "const {generateInvalidEmails} = require('./test-data/userDataGenerator'); const invalid = {...generateValidUser(), email: 'invalidemail.com'}; console.log(JSON.stringify(invalid, null, 2))"
```

#### Step 5: Automate Test Data Generation (Optional JavaScript Script)

**Create:** `test-data/batch-generator.js`

```javascript
const fs = require("fs");
const {
  generateValidUser,
  generateInvalidEmails,
} = require("./userDataGenerator");

// Generate test data for all test cases
const testData = {
  "TC-001": generateValidUser(),
  "TC-002": { ...generateValidUser(), memberType: "teacher" },
  "TC-003": { ...generateValidUser(), memberType: "public" },
  "TC-004": { ...generateValidUser(), username: "" }, // Invalid
  "TC-005": { ...generateValidUser(), username: "a" }, // Too short
  "TC-006": {
    ...generateValidUser(),
    email: generateInvalidEmails().missingAt,
  },
  // ... add more as needed
};

// Save to file
fs.writeFileSync("test-data-complete.json", JSON.stringify(testData, null, 2));
console.log("✅ Test data generated: test-data-complete.json");
```

**Run it:**

```bash
node test-data/batch-generator.js
```

#### Comparison: Manual vs Faker Generated Data

| Aspect              | Manual Entry          | Faker Generated             |
| ------------------- | --------------------- | --------------------------- |
| **Time**            | 5 min per test case   | 10 seconds for all          |
| **Uniqueness**      | May create duplicates | Always unique               |
| **Realism**         | Generic test data     | Realistic names/formats     |
| **Scalability**     | Difficult for 100+ TC | Easy to generate any amount |
| **Reproducibility** | Same data every time  | Different realistic data    |
| **Coverage**        | Limited edge cases    | Can generate boundaries     |

---

## Part 6: Deliverables และ Assessment (Lab Submission)

### 📦 Lab Deliverables

ให้นิสิตส่งงานใน GitHub Repository:

```

library-testing/
├── documentation/
│ └── RTM.xlsx (or link to Google Sheet)
├── test-cases/
│ └── user-management/
│ └── registration/
│ ├── TC-001_Valid_Registration.md
│ ├── TC-002_Min_Username.md
│ ├── ... (อย่างน้อย 20 test cases)
│ └── TC-020_Security_Test.md
├── test-data/
│ ├── userDataGenerator.js
│ ├── batch-generator.js
│ ├── demo-usage.js
│ └── test-data-complete.json
└── README.md (สรุปสิ่งที่ทำใน Lab 4)

```

---

## Part 6: Deliverables และ Assessment (Lab Submission)

### 📦 Lab Deliverables

ให้นิสิตส่งงานใน GitHub Repository:

```

library-testing/
├── documentation/
│ └── RTM.xlsx (or link to Google Sheet)
├── test-cases/
│ └── user-management/
│ └── registration/
│ ├── TC-001_Valid_Registration.md
│ ├── TC-002_Min_Username.md
│ ├── ... (อย่างน้อย 20 test cases)
│ └── TC-020_Security_Test.md
├── test-data/
│ ├── userDataGenerator.js
│ ├── demo-usage.js
│ └── test-data.json
└── README.md (สรุปสิ่งที่ทำใน Lab 4)

```

### ✅ Submission Checklist

**1. Requirements Traceability Matrix (RTM)**

- [ ] RTM มี columns ครบถ้วน (Req ID, Description, Test Cases, Status, Defects)
- [ ] Map ทุก requirement (FR-001 ถึง FR-007) กับ test cases
- [ ] แสดง backward traceability (test cases → requirements)
- [ ] มี summary metrics dashboard
- [ ] File: `documentation/RTM.xlsx` หรือ link to Google Sheet

**2. Test Cases (20+ cases)**

- [ ] Test cases ใช้ template ที่กำหนด
- [ ] มี test case IDs ที่ชัดเจน (TC-001, TC-002, ...)
- [ ] แยก positive, negative และ edge cases
- [ ] Test steps เขียนชัดเจน step-by-step
- [ ] Expected results ระบุครบถ้วน
- [ ] Link กลับไปยัง requirements
- [ ] Files: `test-cases/user-management/registration/TC-*.md`

**3. Test Case Management**

- [ ] GitHub Issues labels สร้างครบ
- [ ] Issue template สำหรับ test cases
- [ ] สร้างอย่างน้อย 5 test cases ใน GitHub Issues
- [ ] Tag และ organize ได้ถูกต้อง

**4. Test Data Generator**

- [ ] File `userDataGenerator.js` ทำงานได้ (run without errors)
- [ ] Generate valid users ได้
- [ ] Generate invalid data สำหรับ negative tests
- [ ] มี functions สำหรับ boundary values
- [ ] มี demo usage examples
- [ ] Export to JSON ได้

**5. Documentation**

- [ ] README.md อธิบายสิ่งที่ทำใน Lab 4
- [ ] Installation/Setup instructions
- [ ] Examples ของการใช้งาน test data generator
- [ ] Link ไปยัง RTM และ test cases

### 📊 Grading Rubric (60 points)

| Criteria                | Points | Details                                                                                 |
| ----------------------- | ------ | --------------------------------------------------------------------------------------- |
| **RTM Quality**         | 15     | - Complete mapping (7)<br>- Accurate traceability (5)<br>- Summary metrics (3)          |
| **Test Cases (15 TC)**  | 25     | - Quality & completeness (10)<br>- Positive/Negative coverage (8)<br>- Traceability (7) |
| **Test Management**     | 10     | - GitHub setup (5)<br>- Issue organization (5)                                          |
| **Test Data Generator** | 5      | - Basic functionality works                                                             |
| **Documentation**       | 5      | - README clarity & instructions                                                         |

**เกณฑ์การให้คะแนน:**

- 55-60: A (ดีมาก)
- 45-54: B (ดี)
- 35-44: C (พอใจ)
- < 35: F (ต้องทำใหม่)

---

## 🆘 Common Issues และ Solutions (ปัญหาทั่วไปและวิธีแก้)

### Issue 1: Faker สร้างรหัสผู้ใช้ซ้ำกัน (Faker generates duplicate usernames)

**ปัญหา:** เมื่อสร้าง test data ซ้ำหลาย ๆ ครั้ง อาจเกิด username ที่ซ้ำกัน

**วิธีแก้:**

```javascript
// เพิ่มเวลาหรือตัวเลขสุ่ม เพื่อให้ username ไม่ซ้ำ
username: `${faker.internet.userName()}_${Date.now()}`;
// ตัวอย่าง: john_doe_1736961234567
```

### Issue 2: RTM formulas ไม่อัปเดต (RTM formulas not updating)

**ปัญหา:** หลังจากกรอกข้อมูลใน RTM สูตร (formulas) ไม่คำนวณค่าใหม่

**วิธีแก้:**

**สำหรับ Excel:** เลือก Ctrl+A แล้วกด Ctrl+Alt+F9 เพื่อบังคับคำนวณใหม่
**สำหรับ Google Sheets:** Auto-updates ตัวเอง (แนะนำใช้ Sheets มากกว่า Excel)

### Issue 3: ไม่รู้จะเขียน Test Cases อย่างไร

**ปัญหา:** นิสิตสับสนกับโครงสร้าง หรือไม่รู้ว่าต้องเขียนอะไร

**วิธีแก้:**

1. ดูตัวอย่าง TC-001 (Positive test) และ TC-004 (Negative test) ใช้เป็น template
2. เริ่มจาก Positive cases ก่อน แล้วค่อย Negative cases
3. ตรวจสอบให้มี: Test Case ID, Objective, Preconditions, Test Data, Test Steps, Expected Results, Traceability

### Issue 4: GitHub Issues template ไม่ทำงาน (GitHub Issues template ไม่ work)

**ปัญหา:** เมื่อสร้าง issue ใหม่ ไม่เห็น template ที่สร้างไว้

**วิธีแก้:**

- ตรวจสอบตำแหน่งไฟล์: `.github/ISSUE_TEMPLATE/test_case.md` (ตัวใหญ่)
- ตรวจสอบ YAML front matter: `name: Test Case`, `title: "[TEST] TC-XXX: "`
- Push ไป GitHub: `git add .github/ISSUE_TEMPLATE/test_case.md && git commit -m "Add test case template" && git push origin main`

---

## 📚 Additional Resources

**Test Case Writing:**

- [IEEE 829 Test Documentation Standard](https://standards.ieee.org/standard/829-2008.html)
- [ISTQB Test Case Design Techniques](https://www.istqb.org/)

**Faker.js:**

- [Official Faker.js Documentation](https://fakerjs.dev/)
- [Faker.js Guide](https://fakerjs.dev/guide/)

**RTM Best Practices:**

- [Requirements Traceability Matrix Template](https://www.guru99.com/traceability-matrix.html)

---

## 🔜 Preview: Next Week (Week 5) - การเตรียมตัวสำหรับสัปดาห์หน้า

### ✨ Black Box Testing Techniques (เทคนิกการทดสอบ Black Box)

สัปดาห์หน้าเราจะเรียนรู้เทคนิกขั้นสูง:

1. **Equivalence Partitioning** - แบ่งข้อมูล input เป็น groups เช่น age 0-17 (child), 18-60 (adult), 61+ (senior)
2. **Boundary Value Analysis** - ทดสอบขอบเขต (boundaries) เช่น min, max, min-1, max+1
3. **Decision Table Testing** - ใช้ตารางแสดง combinations ของ conditions
4. **State Transition Testing** - ทดสอบการเปลี่ยนสถานะ เช่น Available → Borrowed → Returned

### 📚 การเตรียมตัว (Preparation)

**ต้องทำ:**

1. **ทบทวนแนวคิด:** Review boundaries และ partitions concepts, เข้าใจ "boundary" และ "partition"
2. **ศึกษา Business Rules:** Understand Book Borrowing (นักเรียน max 2 เล่ม, อาจารย์ max 3 เล่ม, Borrowing period 14 วัน)
3. **ศึกษา State Machines:** ทำความเข้าใจ state transitions, วาดแผนภาพ, ระบุ valid/invalid transitions

### 📝 Homework (การบ้านต้องส่งก่อน Week 5)

- [ ] ✅ Complete all 20+ test cases (TC-001 ถึง TC-025+)
- [ ] ✅ Finish RTM กับ summary dashboard
- [ ] ✅ Practice using faker.js สร้าง test data
- [ ] ✅ Start thinking about Book Search test scenarios

### 💡 Tips สำหรับความเร็จ

- ✅ Test ทั้ง happy path และ unhappy path
- ✅ Verify database changes ไม่เพียง UI
- ✅ ใช้ generated test data จาก faker.js
- ✅ Document ทุก test steps อย่างชัดเจน
- ✅ Link test cases ไป requirements เสมอ- Complete all 20+ test cases
- Finish RTM
- Practice using faker.js
- Start thinking about Book Search test scenarios

---

## 📚 Reference Files

### 1. Test Case Template: TC-001.md

**Location:** `test-cases/member-management/registration/TC-001.md`

**Sections:**

- Test Case Information
- Description
- Preconditions
- Test Data (JSON)
- Test Steps
- Expected Results
- Actual Results
- Defects
- Traceability

### 2. Test Data Generator: generator.js

**Location:** `test-data/generator.js`

**Functions:**

- generateMemberCode()
- generateValidMember()
- generateBoundaryTestData()
- generateNegativeTestData()
- generateValidTestDataset()

**Run:** `node generator.js`

### 3. RTM Template: RTM_TEMPLATE.md

**Location:** `documentation/RTM_TEMPLATE.md`

**Contents:**

- Requirements FR-001 to FR-009
- Test case mapping
- Defects tracking
- Coverage analysis

---
