Back to notes
mastery-backend-express
Featured

Express.js Testing Mastery: มั่นใจทุกการ Deploy ด้วย Integration Test

เลิกใช้ Postman ยิงมือ! เจาะลึกการทำ Integration Test ด้วย Jest & Supertest เพื่อให้ API ของคุณทำงานได้ถูกต้องและไม่พังเมื่อแก้โค้ด

January 30, 20262 min read readNNexis by Seereen

🛑 1. The Problem First: "แก้จุดนี้ พังจุดโน้น" (The Regression Nightmare)

ลองนึกถึงความรู้สึกตอนที่คุณแก้โค้ดเปลี่ยนชื่อ Field ใน Database แล้วต้องมานั่งเปิด Postman ไล่ยิงเช็ค 20 API เพื่อดูว่ามีอะไรพังไหม:

HLJS JAVASCRIPT
// ❌ Naive Approach: ไม่เขียน Test เลย!
// "เมื่อวานยังรันได้อยู่เลยนะพี่..." 🌋 พัง! เมื่อระบบใหญ่ขึ้น การเช็คคนเดียวเป็นเรื่องที่เป็นไปไม่ได้
// และความผิดพลาดเพียงจุดเดียวอาจทำให้ระบบล่มทั้งแอป (Global Failure)

ปัญหา: ยิ่งแอปใหญ่ขึ้น ความสัมพันธ์ระหว่างฟังก์ชันยิ่งซับซ้อน การแก้ไขจุดเล็กๆ (เช่น Middleware) อาจไปกระทบระบบสำคัญอย่างระบบจ่ายเงินโดยที่คุณไม่รู้ตัว นี่คือความเสี่ยงมหาศาลที่ Senior Developer จะไม่ยอมให้เกิดขึ้นครับ การเขียน Test คือการทำ "ประกันภัย" ให้กับโค้ดของคุณนั่นเอง


💡 2. Real-Life Analogy: การตรวจสอบความปลอดภัยล่วงหน้า (Pre-flight Checklist)

  • Unit Test: เหมือนการเช็ค "หลอดไฟทีละดวง" ว่าติดไหม (เช็คฟังก์ชันเล็กๆ แยกขาดจากตัวอื่น)
  • Integration Test: เหมือนการเช็ค "ระบบไฟทั้งบ้าน". คุณลองเปิดสวิตช์หน้าบ้าน แล้วดูว่าไฟในห้องครัวติดไหม (เช็คว่า Route -> Middleware -> Controller -> Database ทำงานร่วมกันได้จริงไหม)
  • Supertest: เหมือน "หุ่นยนต์ทดสอบแรงกด". ที่คอยกดปุ่มรัวๆ แทนคุณ เพื่อดูว่าเมื่อไหร่มันจะพัง

🚀 3. Execution Journey: มหากาพย์การยิง Request จำลอง

เราจะใช้ Jest เป็นคนคุมกฎ และ Supertest เป็นคนลงมือยิง

🛠 Step-by-step:

  1. The Setup: เตรียม Express App แบบไม่เปิดพอร์ต (app.listen) เพื่อให้ Test รันได้ไว
  2. The Request: ใช้ Supertest ยิง HTTP Method (GET, POST, etc.) ไปยัง Route ที่ต้องการ
  3. The Expectation: ตรวจสอบ Status Code และโครงสร้าง JSON ที่ได้
  4. The Cleanup: ล้างข้อมูลใน Database ทิ้งหลังจบการทดสอบทุกครั้งเพื่อให้ได้ค่าที่ "สะอาด" ใหม่เสมอ
HLJS JAVASCRIPT
// ✅ Best Practice: การทำ API Integration Test (Supertest)
const request = require("supertest");
const app = require("../app");

describe("POST /api/v1/users", () => {
  it("ควรจะสร้าง User ใหม่ได้สำเร็จ", async () => {
    const res = await request(app)
      .post("/api/v1/users")
      .send({ email: "test@example.com", name: "Senior" });

    expect(res.status).toBe(201); // 🛠 เช็คความถูกต้องระดับ HTTP
    expect(res.body.email).toBe("test@example.com"); // 🛠 เช็คความถูกต้องระดับ Data
  });
});

🪤 4. The Junior Trap: ความหายนะของ "Database ตัวจริง"

จูเนียร์มักจะเผลอเขียน Test ที่ไปสร้างข้อมูลทับ Database ของเพื่อนร่วมทีม:

HLJS JAVASCRIPT
// ❌ Junior Trap: ใช้ DB เดียวกันกับ Development รัน Test
// 🌋 พัง! ข้อมูล Test จะไปปนกับข้อมูลจริง ทำให้ตอนรันแอปมึนงง
// และที่ร้ายที่สุดคือ Test ข้อแรกอาจจะเปลี่ยนข้อมูลที่ Test ข้อสองต้องใช้ ทำให้ผลลัพธ์เพี้ยน (Flaky Tests)

ระวัง: การรัน Test ต้องเป็น "Isolated Environment" เสมอ ✅ การแก้ไข: ใช้ Database แยกเฉพาะสำหรับ Test (เช่น Postgres_Test) หรือใช้เทคนิค Database Transaction ที่จะ Rollback (ดึงข้อมูลกลับ) ทุกครั้งที่ Test จบหนึ่งข้อครับ


⚖️ 5. The Why Matrix: ท่าไหนคุ้มค่าที่สุด?

หัวข้อUnit Test (รายตัว)Integration Test (ทั้งระบบ)
ความง่ายเขียนง่ายและเร็วเขียนยากกว่าเล็กน้อย (ต้องต่อ DB)
ความอุ่นใจต่ำ (ไม่รู้ว่าต่อกันแล้วพังไหม)⚡⚡⚡ สูงมาก (รู้ว่าทั้งด่านผ่านแน่นอน)
ความเร็วในการรัน⚡⚡⚡ เร็วมากช้ากว่า (เพราะมีการคุยกับ DB จริง)
ความพึงพอใจต่อ Costเหมาะกับ Logic ซับซ้อน🚀 คุ้มค่าที่สุด สำหรับโปรเจกต์ API

🎓 6. Senior Mindset Summary

การเป็น Senior คือการมองว่า "เราไม่ได้เขียน Test เพื่อหาบั๊ก แต่เขียนเพื่อให้เรากล้าแก้ไขโค้ด (Fearless Refactoring)". เมื่อมี Test ที่แข็งแรงหุ้มแอปไว้ คุณจะกล้าปรับปรุงระบบให้ดีขึ้นโดยไม่ต้องกังวลว่าความพ่ายแพ้จะเกิดขึ้นในวันพรุ่งนี้ครับ!

Share this note

© 2026 My Notes by Seereen