🛑 1. The Myth: "100% Test Coverage = 0 Bugs"
มือใหม่หลายคนเชื่อว่าพอยิ่งมี Test เยอะเท่าไหร่แอปยิ่งดี แต่ความจริงคือ "การเทสต์ทุกอย่างมีราคาที่ต้องจ่าย" (Maintenance Cost) ครับ:
- คุณต้องเสียเวลาเขียนเทสต์
- คอมพิวเตอร์ต้องเสียเวลารันเทสต์ทุกครั้งที่แก้โค้ด
- ถ้าคุณเปลี่ยน Logic เล็กน้อย แต่เทสต์พัง 50 ตัว คุณจะเริ่มขี้เกียจเขียนเทสต์
Senior Solution: เราต้องใช้ Testing Pyramid เพื่อเลือกว่าส่วนไหนควรเทสต์หนัก ส่วนไหนควรเทสต์เบา เพื่อให้ได้ความมั่นใจสูงสุดในราคาที่ต่ำที่สุดครับ
💡 2. Real-Life Analogy: การตรวจรับเครื่องบินก่อนขึ้นบิน
- Unit Tests (ฐานพีระมิด): เหมือนการเช็ก "น็อตทุกตัว" และสายไฟทุกเส้นในโรงงาน มันง่าย เร็ว และถ้าพังเรารู้อันที่พังทันที (เช็กได้เป็นล้านตัวในไม่กี่วินาที)
- Integration Tests (กลางพีระมิด): เหมือนการเช็ก "เครื่องยนต์" ว่าทุกชิ้นส่วนทำงานร่วมกันได้ไหม (ช้ากว่าหน่อย เพราะต้องใช้อุปกรณ์หลายอย่างประกอบกัน)
- E2E Tests (ยอดพีระมิด): เหมือนการ "เอานักบินขึ้นไปบินจริง" บนท้องฟ้า (ช้าที่สุด แพงที่สุด แต่ให้ความมั่นใจที่สุดว่าเครื่องบินบินได้จริง)
- หัวใจสำคัญ: คุณไม่สามารถบินจริง (E2E) ทุกวันวันละ 1,000 รอบได้ แต่คุณเช็กน็อต (Unit Test) ได้ทุกวินาทีครับ
🚀 3. Execution Journey: 3 เลเยอร์ของการเทสต์แบบมืออาชีพ
ในฐานะ Fullstack Developer ผมวางแผนการเทสต์ดังนี้ครับ:
🛠 Step-by-step:
- Unit Tests (80%): โฟกัสที่ Logic เพียวๆ เช่น "ถ้าคำนวณราคาสินค้าที่มีส่วนลด 10% ผลลัพธ์ต้องถูกต้อง" (ใช้ Jest/Vitest)
- Integration Tests (15%): โฟกัสที่การเชื่อมต่อ เช่น "เมื่อยิง API นี้ NestJS ต้องไปบันทึกข้อมูลลง Database จริงๆ ได้ถูกตาราง"
- End-to-End (E2E) Tests (5%): โฟกัสที่ Happy Path สำคัญที่สุด เช่น "ลูกค้าสามารถหยิบสินค้าใส่ตะกร้าและจ่ายเงินจนสำเร็จได้จริง" (ใช้ Playwright/Cypress)
// ✅ ตัวอย่าง Unit Test ที่ดี (ทดสอบแค่ Logic เดียว)
describe("DiscountCalculator", () => {
it("should apply 10% discount correctly", () => {
const result = calculatePrice(100, 0.1);
expect(result).toBe(90);
});
});
🪤 4. The Junior Trap: "Brittle Tests" (เทสต์ที่เปราะบาง)
จูเนียร์มักจะเขียนเทสต์ที่ผูกติดกับดีไซน์ UI เช่น "ต้องมีปุ่มสีแดงอยู่ที่พิกัด X, Y" หรือ "ต้องใช้ฟังก์ชันชื่อ A" พอเปลี่ยนชื่อฟังก์ชันหรือย้ายปุ่มนิดเดียว เทสต์ก็พังทันที
- ปัญหา: คุณจะเสียเวลา "ซ่อมเทสต์" มากกว่าเขียนฟีเจอร์ใหม่
- ✅ การแก้ไข: จงเทสต์ที่ "พฤติกรรม (Behavior)" ไม่ใช่เทสต์ที่ "การทำงานภายใน (Implementation)". ให้ถามว่า "ถ้ากดปุ่มนี้แล้ว ตัวเลขยอดเงินต้องเพิ่มขึ้น" ไม่ว่าปุ่มจะสีอะไรหรือเรียกฟังก์ชันชื่ออะไร ผลลัพธ์ต่างหากคือสิ่งที่สำคัญครับ
⚖️ 5. The Strategy Matrix: เมื่อไหร่ควรเขียนเทสต์อะไร?
| ประเภท | ความเร็ว | ความแม่นยำ (Confidence) | ค่าบำรุงรักษา |
|---|---|---|---|
| Unit Test | 🚀 เร็วปรี๊ด | เจาะจงเฉพาะจุด | ต่ำ (เขียนง่าย) |
| Integration | 🐢 ปานกลาง | มั่นใจว่าระบบคุยกันรู้เรื่อง | ปานกลาง |
| E2E Test | 🐌 ช้ามาก | 💎 มั่นใจที่สุดว่าผู้ใช้ใช้งานได้ | สูง (พังง่ายถ้า UI เปลี่ยน) |
🎓 6. Senior Mindset Summary
เป้าหมายของการเทสต์ไม่ใช่ "ความสมบูรณ์แบบ" แต่คือ "การที่คุณกล้ากด Deploy ในวันศุกร์ตอนเย็น" อย่างมั่นใจครับ ถ้าเทสต์ของคุณไม่ช่วยให้คุณมั่นใจขึ้น มันก็คือขยะที่เป็นภาระของทีม คุณภาพซอฟต์แวร์เริ่มต้นที่การออกแบบ ไม่ใช่การไปนั่งไล่เทสต์ทีหลังครับ!