Vitest · Assertions พื้นฐาน
`.toThrow()`
ตรวจ function ที่ควรโยน error เมื่อถูกเรียก
toThrow()
toThrow() ใช้ตรวจ synchronous function ที่ควร throw error เมื่อได้รับ input ที่ไม่ถูกต้อง สิ่งสำคัญคือส่ง function เข้า expect เพื่อให้ matcher เป็นผู้เรียก function ภายใน ถ้าเรียก function ก่อน expect error จะหลุดออกมาก่อน assertion
ใช้ function wrapper เพื่อให้ Vitest จับ error ได้
กฎสำคัญ
ส่ง function ไม่ใช่ผลลัพธ์
toThrow ต้องได้รับ function ที่ยังไม่ถูกเรียก เพื่อให้ matcher ควบคุมจังหวะการเรียกและตรวจ error behavior ได้
ให้ matcher ตรงกับคำถาม
เลือกวิธีตรวจจาก behavior ที่ต้องการ ไม่เลือกจากชื่อที่ดูคุ้นหรือสั้นที่สุด
แกะตัวอย่างทีละขั้น
อย่าอ่าน matcher เป็นคำสั่งเดี่ยว ให้ตามเส้นทางของข้อมูลจาก input ไป actual แล้วดูว่า matcher ตัดสิน actual อย่างไร ตารางนี้แยกสามช่วงของตัวอย่างออกจากกันเพื่อช่วยให้เริ่มอ่านได้ทีละส่วน
| ขั้น | สิ่งที่เกิดขึ้น |
|---|---|
| เตรียม function | `requireTitle` จะ throw เมื่อได้รับ title ว่าง |
| ยังไม่เรียกทันที | ห่อการเรียกด้วย `() => requireTitle("")` เพื่อส่ง function ให้ matcher |
| ตรวจ error | `.toThrow("TITLE_REQUIRED")` เป็นผู้เรียก function และตรวจข้อความ error |
ถ้าแก้ค่าตั้งต้นในตัวอย่าง ให้ถามต่อว่า toThrow() ยังตรงกับคำถามเดิมหรือไม่ ตัวอย่างที่ดีไม่ได้แค่ทำให้ test ผ่าน แต่ทำให้เราเข้าใจว่ากำลังพิสูจน์ behavior ใด
รูปแบบที่ถูกและผิด
| สถานการณ์ | วิธีคิด |
|---|---|
| ต้องการตรวจ function ที่ throw | expect(() => run()).toThrow() |
| เรียก run() ก่อน expect | error จะเกิดก่อน matcher และ test อ่านยากหรือควบคุมไม่ได้ |
| function คืน Promise ที่ reject | ยังไม่ใช่ toThrow; ใช้ rejects ใน phase Async |
อย่าตรวจเกิน contract
ถ้า requirement สนใจเฉพาะ property หรือ state หนึ่งอย่าง ให้ตรวจเท่านั้น การ assert รายละเอียดที่ไม่ใช่สัญญาจะทำให้ test เปราะโดยไม่เพิ่มความมั่นใจ
แบบฝึก: เลือกและเขียน matcher
เขียน test สำหรับ title ที่ว่างและต้อง throw error
งานที่ต้องทำ
- สร้าง function requireTitle
- ให้ function throw เมื่อ title ว่าง
- ส่ง callback เข้า expect แล้วตรวจข้อความ error
ลองทำด้วยตัวเองก่อน แล้วค่อยเปิดเฉลยเพื่อเทียบแนวคิดและรายละเอียด