Vitest · Mocks และ Spies
`.mockReturnValue()`
กำหนดค่าที่ mock function จะคืนกลับแบบ synchronous
mockReturnValue()
mockReturnValue() กำหนดค่าที่ mock function จะคืนทุกครั้งที่ถูกเรียก เหมาะกับ dependency แบบ synchronous ที่ test ต้องควบคุมผลลัพธ์เพื่อให้ตรวจ logic ของ subject ได้ตรงจุด
แยกการกำหนด behavior ของ mock ออกจากการตรวจ subject
กฎสำคัญ
ตรวจ interaction ที่เป็น contract
mock matcher ควรพิสูจน์การสื่อสารที่จำเป็นต่อ behavior ไม่ใช่ตรวจทุกการเรียกภายใน
อ่าน call history เป็นหลักฐาน
จำนวนครั้งและ arguments ช่วยบอกว่า boundary ได้รับข้อมูลตามที่คาดหรือไม่
แกะ mock จากการเตรียมไปถึง assertion
ตัวอย่าง mock ควรอ่านเป็นลำดับ: สร้างตัวแทน, กำหนดหรือปล่อยให้มันบันทึก behavior, เรียก subject และตรวจหลักฐานที่ผ่าน boundary ตารางนี้ช่วยแยกขั้นที่มักถูกเขียนติดกันจนผู้เริ่มต้นมองไม่ออก
| ขั้น | สิ่งที่เกิดขึ้น |
|---|---|
| สร้างตัวแทน | สร้าง getCurrentFilter ด้วย vi.fn() จึงยังไม่มีงานจริงให้ทำ |
| กำหนดคำตอบ | ให้ mockReturnValue("active") เพื่อควบคุมค่าที่ dependency จะคืน |
| ตรวจ subject | เรียก listLabel แล้วตรวจว่า logic ได้คำตอบ active จาก boundary |
อย่าเริ่มจากการจำชื่อ matcher อย่างเดียว ให้ถามก่อนว่า mockReturnValue() กำลังพิสูจน์การสื่อสารข้อใด และการเรียกนั้นเป็น contract จริงหรือเป็นเพียงรายละเอียดภายใน
เลือก assertion ให้พอดี
| สถานการณ์ | แนวทาง |
|---|---|
| dependency คืนค่าปกติทันที | mockReturnValue(value) |
| dependency คืน Promise | mockResolvedValue(value) |
| ต้องการค่าต่างกันแต่ละ call | ใช้ once API ในขั้นที่เหมาะสม ไม่ขยาย scope หน้านี้ |
Mock ไม่ใช่เป้าหมายของ test
เริ่มจาก behavior ของ Task service แล้วค่อยตรวจ interaction ที่จำเป็นต่อ behavior นั้น ถ้าเปลี่ยน implementation แล้วยังรักษา contract ได้ test ไม่ควร fail เพียงเพราะรูปแบบภายในเปลี่ยน
แบบฝึก: ตรวจ interaction
กำหนด mock ให้ getFilter คืนคำว่า completed แล้วตรวจ label
งานที่ต้องทำ
- สร้าง getFilter ด้วย vi.fn()
- กำหนด return value เป็น completed
- เรียก function ที่ใช้ getFilter แล้วตรวจผลลัพธ์
ลองทำด้วยตัวเองก่อน แล้วค่อยเปิดเฉลยเพื่อเทียบแนวคิดและรายละเอียด