Testing 101: Unit, Integration และ E2E คืออะไร? ต่างกันยังไง? สรุปจบในที่เดียว

แก้บั๊กทีนึง โผล่มาใหม่อีก 3 ที่! 😱
ใครเคยเจอเหตุการณ์แบบนี้บ้างครับ? แก้โค้ดหน้า A เสร็จ มั่นใจมากว่าผ่าน แต่พอดันขึ้น Production ปุ๊บ หน้า B พัง หน้า C เน่า... จนต้อง Rollback กันวุ่นวาย
ปัญหาเหล่านี้แก้ได้ด้วยสิ่งที่เรียกว่า "Automated Testing" ครับ วันนี้เราจะมาเจาะลึก 3 พี่น้องพื้นฐานอย่าง Unit Test, Integration Test และ E2E Test กัน!

🧩 Unit Test: เช็คจุดเล็กๆ ให้ชัวร์
Unit Test คือการทดสอบ "หน่วยที่เล็กที่สุด" ของโค้ดครับ มักจะเป็น Function หรือ Class เดียวโดดๆ โดยเราจะไม่สนใจว่ามันจะไปต่อกับ Database หรือ API ข้างนอกยังไง (เราจะจำลองหรือ Mock สิ่งเหล่านั้นขึ้นมาแทน)
เปรียบเทียบง่ายๆ: เหมือนเราผลิตน็อต เราก็เช็คแค่ว่า "น็อตตัวนี้เกลียวสวยไหม แข็งแรงไหม" ไม่ต้องสนว่ามันจะไปข้นกับอะไร
✅ ข้อดี
- เร็วมาก: รันเป็นพันๆ เทสต์ได้ในวิเดียว
- หาง่าย: ถ้าพัง เรารู้ทันทีว่าพังที่บรรทัดไหน เพราะมันเทสต์แค่จุดเดียว
💡 ตัวอย่างโค้ด (Jest/Vitest)
// function ที่เราจะ test
function add(a: number, b: number) {
return a + b;
}
// ตัว Unit Test
test('should add 1 + 2 to equal 3', () => {
expect(add(1, 2)).toBe(3);
});
🔗 Integration Test: เช็คการทำงานร่วมกัน
Integration Test คือการเอาหลายๆ Unit มา "ประกอบร่าง" แล้วดูว่ามันทำงานร่วมกันได้ไหม เช่น Function นี้เรียก Database แล้วได้ค่าถูกต้องไหม หรือ Component นี้กดปุ่มแล้ว API ถูกยิงออกไปจริงไหม
เปรียบเทียบง่ายๆ: เอาน็อตเมื่อกี้มาลองขันเข้ากับแผ่นเหล็ก ดูว่า "เกลียวมันเข้ากันได้พอดีไหม"
✅ ข้อดี
- สมจริง: มั่นใจได้ว่าระบบทำงานได้จริง ไม่ใช่แค่ Logic ถูกแต่ต่อผิด
- จับบั๊กการส่งข้อมูล: มักจะเจอปัญหาตอนส่งค่าข้าม Function หรือข้าม Service
💡 ตัวอย่างโค้ด
// สมมติเราจะ Test การลงทะเบียน User
test('should create user in database', async () => {
// 1. เรียก Service เพื่อสร้าง User จริงๆ
const user = await userService.create({ name: 'John' });
// 2. เช็คว่าใน Database มี User นี้อยู่จริงไหม
const dbUser = await db.findUser(user.id);
expect(dbUser).toBeDefined();
expect(dbUser.name).toBe('John');
});
🌐 E2E Test: เช็คตั้งแต่ต้นจนจบ (End-to-End)
E2E Test คือการทดสอบที่จำลองพฤติกรรมของ "ผู้ใช้จริง" ครับ โดยตัวทดสอบจะเปิดเบราว์เซอร์ขึ้นมาจริงๆ แล้วทำตามขั้นตอนที่ผู้ใช้ทำ เช่น "เปิดหน้าเว็บ -> กรอก User -> กด Login -> เช็คว่าหน้า Dashboard ขึ้นไหม"
เปรียบเทียบง่ายๆ: เหมือนเราเอาเครื่องจักรทั้งเครื่องมาลองรันดูจริงๆ ว่า "กดปุ่มสตาร์ทแล้ว แขนกลขยับ สายพานเดิน และของออกมาได้จริงไหม"
✅ ข้อดี
- มั่นใจที่สุด: เพราะมันเทสต์เหมือนที่ User เจอจริงๆ ถ้าผ่านคือชัวร์ว่าใช้งานได้
- จับบั๊ก UI/UX: เห็นภาพรวมทั้งหมด ตั้งแต่ Frontend ยัน Backend
⚠️ ข้อควรระวัง
- ช้า: การเปิดเบราว์เซอร์และทำตาม Step ใช้เวลานานกว่า Unit Test มากๆ
- เปราะบาง (Flaky): ถ้าหน้าเว็บมีการเปลี่ยน Class หรือเปลี่ยนตำแหน่งปุ่มเพียงนิดเดียว Test อาจจะพังได้ง่ายๆ
🛠 เครื่องมือยอดฮิต:
- Playwright (แนะนำตัวนี้ครับ แรงและดีมาก)
- Cypress
⛰️ The Testing Pyramid (สามเหลี่ยมแห่งการเทสต์)
เพื่อให้การเทสต์มีประสิทธิภาพ เราควรยึดหลัก Testing Pyramid ครับ:
- Unit Tests (ฐานล่างสุด - กว้างที่สุด): ควรมีเยอะที่สุด (70%) เพราะเขียนง่าย รันไว
- Integration Tests (ตรงกลาง): มีพอสมควร (20%) เพื่อเช็คจุดเชื่อมต่อสำคัญๆ
- E2E Tests (ยอดบนสุด): มีน้อยที่สุด (10%) จำลองการกดของ User จริงๆ เพราะรันช้าและดูแลยาก
✨ สรุป: เริ่มจากตรงไหนดี?
ถ้าคุณยังไม่เคยเขียน Test เลย ผมแนะนำให้เริ่มจาก Unit Test กับ Function สำคัญๆ ที่มี Logic ซับซ้อนก่อนครับ (เช่นพวกคำนวณราคา, ตัดสต็อก) เพราะมันเริ่มง่ายและเห็นผลทันที
การเขียน Test อาจจะดูเสียเวลาในตอนแรก แต่เชื่อเถอะครับว่าในระยะยาว มันคือ "ฮีโร่" ที่จะช่วยชีวิตคุณจากบั๊กมหาภัยในคืนวันศุกร์แน่นอน!
Happy Testing ครับทุกคน! 🦆✨