# สัปดาห์ที่ 9: Automated Testing Frameworks & Test Automation

## สารบัญ

- [วัตถุประสงค์การเรียนรู้](#-วัตถุประสงค์การเรียนรู้)
- [บทบรรยาย](#-บทบรรยาย)
  - [ส่วนที่ 1: Testing Frameworks & Test Automation](#ส่วนที่-1-testing-frameworks--test-automation)
    - [1.1 ทำไมต้องทดสอบ](#11-ทำไมต้องทดสอบ)
    - [1.2 Testing Pyramid](#12-testing-pyramid)
    - [1.3 Unit Testing Framework](#13-unit-testing-framework)
    - [1.4 Test-Driven Development (TDD)](#14-test-driven-development-tdd)
    - [1.5 Integration Testing](#15-integration-testing)
    - [1.6 Regression Testing](#16-regression-testing)
  - [ส่วนที่ 2: Test Data & Setup/Teardown](#ส่วนที่-2-test-data--setupteardown)
- [กิจกรรม (Activities)](#-กิจกรรม-activities)
  - [Activity 1: Write Unit Tests](#activity-1-write-unit-tests-35-นาที)
  - [Activity 2: Write Integration Tests with Test Data](#activity-2-write-integration-tests-with-test-data-25-นาที)
- [Homework](#-homework)
  - [Homework 1: Testing Strategy](#homework-1-testing-strategy-1-2-pages)
  - [Homework 2: Write 10-15 Unit Tests](#homework-2-write-10-15-unit-tests)
- [D3 Week 9 Deliverables](#-d3-week-9-deliverables)
- [Checklist: Ready for Week 10?](#-checklist-ready-for-week-10)
- [Key References](#-key-references)

---

## 📋 วัตถุประสงค์การเรียนรู้

หลังจากเรียนในสัปดาห์นี้ นักศึกษาจะสามารถ:

1. **Unit Testing Framework:** เขียน unit tests โดยใช้ Jest/Mocha
2. **Test-Driven Development (TDD):** Red-Green-Refactor cycle
3. **Integration Testing:** ทดสอบ components ทำงานร่วมกัน + ข้อมูล test
4. **Test Data Management:** Setup/Teardown และ test fixtures
5. **Testing Best Practices:** Naming, Coverage, Assertion อย่างถูกต้อง

---

### ส่วนที่ 1: Testing Frameworks & Test Automation

#### 1.1 ทำไมต้องทดสอบ?

**สถิติ:**

- 40-50% เวลาพัฒนา ใช้ในการทดสอบ
- Bug ที่พบหลัง deployment แพงกว่า 10-100 เท่า
- Automated testing ประหยัดเวลา 20-30% ในระยะยาว

**ผลประโยชน์ที่ได้:**

```
✓ Catch bugs early (ยิ่งเร็วยิ่งดี)
✓ Prevent regression (ไม่ได้ทำลาย feature เก่า)
✓ Increase confidence (Deploy with confidence)
✓ Safe refactoring (เปลี่ยนโค้ดอย่างปลอดภัย)
✓ Save cost in long run (Automation saves money)
```

#### 1.2 Testing Pyramid

```
                    ▲
                   / \
                  /   \
                 / E2E \        (10% - ช้า แพง)
                /-------\
               /         \
              /           \
             /─────────────\
            /               \
           / Integration     \   (20% - ปานกลาง)
          /     Tests        \
         /─────────────────────\
        /                       \
       /                         \  (70% - เร็ว ถูก)
      /       Unit Tests          \
     /─────────────────────────────\
    /_______________________________\

Distribution (Ideal):
- Unit Tests: 70%          ← ทดสอบ 1 method/function
- Integration Tests: 20%   ← ทดสอบ components ร่วมกัน
- E2E Tests: 10%           ← ทดสอบแบบผู้ใช้
```

#### 1.3 Unit Testing Framework

**นิยาม:** ทดสอบ 1 method/function ขึ้น ไม่เกี่ยวกับ dependencies

**Popular Frameworks:**

```
Framework | Language | Features
----------|----------|----------
Jest      | JS/TS    | Fast, Built-in coverage, Mocking ⭐
Mocha     | JS/TS    | Flexible, Async support
JUnit     | Java     | Industry standard
Pytest    | Python   | Simple syntax, Powerful fixtures
```

**ตัวอย่าง Jest:**

```javascript
// ❌ BAD: ขึ้นอยู่กับ database
test("calculate age", () => {
  const user = userService.getUser(1); // database call!
  const age = userService.calculateAge(user);
  expect(age > 0).toBe(true); // ไม่ชัด expectation
});

// ✅ GOOD: isolated, clear
test("calculateAge_ValidDOB_ReturnsCorrectAge", () => {
  // Arrange
  const dob = new Date(2000, 0, 1);
  const user = new User("John", dob);

  // Act
  const age = userService.calculateAge(user);

  // Assert
  expect(age).toBe(24); // ชัด: ต้อง 24 ได้แค่นี้
});
```

**เป้าหมาย Coverage:**

```
- Statement Coverage: >= 80% (รัน 80% ของบรรทัดโค้ด)
- Branch Coverage: >= 80% (ทดสอบ if/else ทั้งหมด)
- Target: 80-90% (practical) vs 100% (unrealistic)

ตัวอย่างตาราง:
- Core business logic: 100%
- Important features: 90% + branch coverage
- Utilities: 80%
- Getters/setters: skip
```

**ตัวอย่าง:**

```javascript
// ❌ BAD: ขึ้นอยู่กับ database
test("calculate age", () => {
  const user = userService.getUser(1); // database call!
  const age = userService.calculateAge(user);
  expect(age > 0).toBe(true); // ไม่ชัด expectation
});

// ✅ GOOD: isolated, clear
test("calculateAge_ValidDOB_ReturnsCorrectAge", () => {
  // Arrange
  const dob = new Date(2000, 0, 1);
  const user = new User("John", dob);

  // Act
  const age = userService.calculateAge(user);

  // Assert
  expect(age).toBe(24); // ชัด: ต้อง 24 ได้แค่นี้
});
```

**เป้าหมาย Coverage:**

```
- Statement Coverage: >= 80% (รัน 80% ของบรรทัดโค้ด)
- Branch Coverage: >= 80% (ทดสอบ if/else ทั้งหมด)
- Target: 80-90% (practical) vs 100% (unrealistic)

ตัวอย่างตาราง:
- Core business logic: 100%
- Important features: 90% + branch coverage
- Utilities: 80%
- Getters/setters: skip
```

#### 1.5 Integration Testing

**นิยาม:** ทดสอบ components ทำงานร่วมกัน + database (user → order → inventory)

**ตัวอย่าง:**

```javascript
test("createOrder_UpdatesInventory_AndProcessesPayment", async () => {
  // Setup: สร้าง test data
  const product = await db.products.create({
    name: "Laptop",
    price: 999,
    stock: 10,
  });
  const user = await db.users.create({ email: "john@test.com" });

  // Act: สร้าง order
  const order = await orderService.createOrder(user.id, product.id, 2);

  // Assert: ตรวจสอบหลายจุด
  expect(order.status).toBe("completed");
  expect(order.total).toBe(1998); // 999 * 2

  const updatedProduct = await db.products.findById(product.id);
  expect(updatedProduct.stock).toBe(8); // 10 - 2

  const payment = await db.payments.findByOrderId(order.id);
  expect(payment.status).toBe("COMPLETED");
});
```

#### 1.4 Test-Driven Development (TDD)

**คืออะไร?**

การเขียนโค้ด test _ก่อน_ เขียน production code

**Cycle:**

```
1️⃣ Red: เขียน test ที่ fail (code ยังไม่มี)
   test("add_TwoNumbers_ReturnSum", () => {
     expect(add(2, 3)).toBe(5);
   });
   // ❌ Error: add is not defined

2️⃣ Green: เขียน code ให้ test ผ่าน (อย่างง่ายก็ได้)
   const add = (a, b) => a + b;
   // ✅ Test pass!

3️⃣ Refactor: ทำความสะอาด
   // Code is already clean, nothing to refactor
```

**ทำไมทำ TDD?**

```
✅ Fewer late bugs (bug ส่วนมากถูกจับ ตอน Red phase)
✅ Better design (Design by contract)
✅ Documentation (Tests = usage examples)
✅ Confidence (ทำการ refactor อย่างวางใจ)
```

**ตัวอย่างที่ดี:**

```javascript
// CASE: User registration validation

// Step 1: RED - เขียน test ที่ fail
describe("UserService.register", () => {
  test("InvalidEmail_ShouldThrow", () => {
    expect(() => userService.register("invalid-email", "pwd")).toThrow(
      "Invalid email",
    );
  });

  test("ShortPassword_ShouldThrow", () => {
    expect(() => userService.register("john@test.com", "123")).toThrow(
      "Password length >= 8",
    );
  });

  test("ValidInput_ShouldCreateUser", async () => {
    const user = await userService.register("john@test.com", "password123");
    expect(user.email).toBe("john@test.com");
    expect(user.id).toBeDefined();
  });
});

// Step 2: GREEN - เขียน code ให้ test ผ่าน
class UserService {
  async register(email, password) {
    // Validation
    if (!email.includes("@")) throw new Error("Invalid email");
    if (password.length < 8) throw new Error("Password length >= 8");

    // Create user
    const user = { id: uuid(), email, password: hash(password) };
    await db.users.insert(user);
    return user;
  }
}

// Step 3: REFACTOR - ขยับให้สะอาด (optional หากต้องการ)
```

#### 1.6 Regression Testing

**นิยาม:** เช็คว่าฟีเจอร์เก่ายังใช้ได้ หลังจากเพิ่มฟีเจอร์ใหม่

**วิธีทำ:**

```javascript
// เก่า: Login feature - ย่อมต้องใช้ได้
test("login_ValidCredentials_ReturnsJWT", () => {
  const token = auth.login("john@test.com", "password123");
  expect(token).toBeDefined();
});

// ใหม่: ทำ 2FA เพิ่มเข้าไป
test("login_with2FA_RequireOTP", () => {
  // 2FA เพิ่มมา แต่ login เดิมยังต้องใช้ได้
});
```

**ทำไม?**

```
❌ ปัญหาที่มักเจอ:
  - Developer เพิ่มฟีเจอร์ใหม่
  - "Forget" ว่ามี code เก่า ที่ขึ้นต่อกัน
  - Refactor ทำให้โค๊ดเก่ามีโอกาสทำงานผิดพลาด
  → Regression test ช่วยจับ bug นี้!
```

---

### ส่วนที่ 2: Test Data & Setup/Teardown

**Goal:** เข้าใจวิธีการจัดการ test data และสร้างสภาพแวดล้อมทดสอบที่สะอาดสำหรับแต่ละ test

```javascript
// tests/helpers/db.js
const db = require("../../src/database");

async function setupTestDB() {
  // Run migrations
  await db.migrate();

  // Seed test data (optional)
  await db.users.create({
    id: 1,
    email: "test@example.com",
    name: "Test User",
  });

  await db.products.create({
    id: 1,
    name: "Test Product",
    price: 100,
    stock: 10,
  });
}

async function cleanupTestDB() {
  // Clear all tables
  await db.users.deleteAll();
  await db.products.deleteAll();
  await db.orders.deleteAll();

  // Close connections
  await db.close();
}

module.exports = { setupTestDB, cleanupTestDB };
```

**Usage in Tests:**

```javascript
const { setupTestDB, cleanupTestDB } = require("./helpers/db");

describe("Order Service", () => {
  beforeAll(async () => {
    await setupTestDB();
  });

  afterAll(async () => {
    await cleanupTestDB();
  });

  test("should create order successfully", async () => {
    // Test logic here
  });
});
```

**.env.test Configuration:**

```bash
# .env.test
NODE_ENV=test
DATABASE_URL=postgres://postgres:test@localhost:5432/test_db
API_PORT=3001
REDIS_URL=redis://localhost:6379/1
LOG_LEVEL=error
```

---

## 🎯 กิจกรรม (Activities)

### Activity 1: Write Unit Tests (35 นาที)

**ขั้นตอน:**

1. **Select 2-3 functions** (5 min)
   - UserService.register()
   - OrderService.calculateTotal()
   - PaymentProcessor.validate()

2. **Design test cases** (15 min)
   - Valid input → success
   - Invalid input → error
   - Edge cases (null, empty, boundary)

3. **Write & run tests** (15 min)
   ```javascript
   test("register_ValidEmail_CreatesUser", () => {
     // AAA: Arrange, Act, Assert
   });
   ```

**Deliverables:**

- ✅ 10-15 test methods passing
- ✅ Coverage >= 80%

---

### Activity 2: Write Integration Tests with Test Data (25 นาที)

**ขั้นตอน:**

1. **Create test fixtures** (10 min)
   - Write setupTestDB()
   - Write cleanupTestDB()
   - Include sample data

2. **Write integration tests** (10 min)
   - Use setupTestDB() + cleanupTestDB()
   - Test 3-5 workflows ที่เกี่ยว database

3. **Run & verify** (5 min)
   - Tests ผ่าน
   - Data clean up after each test

**Deliverables:**

- ✅ tests/helpers/db.js with setup/cleanup functions
- ✅ 3-5 integration tests using test data

## 📝 Homework

### Homework 1: Testing Strategy (1-2 pages)

เขียนส่วนของโปรเจกต์ของคุณ:

- Testing pyramid: กี่ % unit/integration/E2E?
- Coverage goal?
- Tools?
- Timeline?

### Homework 2: Write 10-15 Unit Tests

Pick 1-2 services จากโปรเจกต์ & test them:

- Coverage >= 80%
- Tests ทั้งหมดผ่าน
- Include edge cases

---

## 📋 D3 Week 9 Deliverables

| Item                      | Points  | Due Date | Notes                          |
| ------------------------- | ------- | -------- | ------------------------------ |
| Unit Tests (80% coverage) | 2.0     | Week 9   | Minimum 10-15 tests            |
| Integration Tests         | 1.5     | Week 9   | 3-5 with test data             |
| Test Data Setup helpers   | 1.0     | Week 9   | setup/cleanup functions        |
| Testing documentation     | 1.5     | Week 9   | Test strategy + plan           |
| **Week 9 Total**          | **6.0** | Week 9   |                                |
| **Week 10 additions**     | **2.0** | Week 10  | CI/CD pipeline setup           |
| **D3 TOTAL**              | **8.0** | Week 10  | (Bonus +2 for coverage report) |

---

## ✅ Checklist: Ready for Week 10?

- [ ] 10+ unit tests written
- [ ] 3-5 integration tests written
- [ ] Coverage 80%+
- [ ] Test data setup & cleanup working
- [ ] No broken tests
- [ ] Documentation complete

---

## 📖 Key References

- [Testing Pyramid - Martin Fowler](https://martinfowler.com/bliki/TestPyramid.html)
- [Jest Documentation](https://jestjs.io/docs/getting-started)
- [TDD: Red-Green-Refactor](https://en.wikipedia.org/wiki/Test-driven_development)
- [Integration Testing Best Practices](https://www.testim.io/blog/integration-testing/)

---

## 💡 TDD Success Stories

**Google:**

- Unit tests: ~50% of Google codebase
- Result: Faster refactoring, fewer bugs

**Etsy:**

- TDD for critical features
- Result: Better code, easier onboarding

**Netflix:**

- Integration tests before deployment
- Result: 99.95% uptime

---

## 🔗 ต่อสัปดาห์ที่ 10

**Next week:** Continuous Integration/Continuous Deployment (CI/CD) Pipeline

- GitHub Actions workflow
- Lint → Build → Test → Deploy
- Deployment strategies (Blue-Green, Rolling, Canary)

---

**Week 9 Focus: Write Tests + Understand TDD**

`
