Vitest · Mocks และ Spies
`.toHaveBeenCalled()`
ตรวจว่า mock หรือ spy ถูกเรียกอย่างน้อยหนึ่งครั้ง
toHaveBeenCalled()
toHaveBeenCalled() ตรวจว่า mock หรือ spy ถูกเรียกอย่างน้อยหนึ่งครั้ง เหมาะเมื่อการเรียก dependency เป็นส่วนหนึ่งของ behavior เช่น เมื่อ complete task แล้วต้องส่ง event แจ้ง notifier
ตรวจว่ามี interaction เกิดขึ้น โดยยังไม่ตรวจจำนวนหรือ argument
กฎสำคัญ
ตรวจ interaction ที่เป็น contract
mock matcher ควรพิสูจน์การสื่อสารที่จำเป็นต่อ behavior ไม่ใช่ตรวจทุกการเรียกภายใน
อ่าน call history เป็นหลักฐาน
จำนวนครั้งและ arguments ช่วยบอกว่า boundary ได้รับข้อมูลตามที่คาดหรือไม่
แกะ mock จากการเตรียมไปถึง assertion
ตัวอย่าง mock ควรอ่านเป็นลำดับ: สร้างตัวแทน, กำหนดหรือปล่อยให้มันบันทึก behavior, เรียก subject และตรวจหลักฐานที่ผ่าน boundary ตารางนี้ช่วยแยกขั้นที่มักถูกเขียนติดกันจนผู้เริ่มต้นมองไม่ออก
| ขั้น | สิ่งที่เกิดขึ้น |
|---|---|
| เตรียม notifier | สร้าง notify mock ที่เก็บประวัติการเรียก |
| เรียก subject | completeAndNotify ทำงานและควรส่ง event ไปยัง notifier |
| ตรวจ interaction | toHaveBeenCalled ยืนยันว่ามีการสื่อสารเกิดขึ้นอย่างน้อยหนึ่งครั้ง |
อย่าเริ่มจากการจำชื่อ matcher อย่างเดียว ให้ถามก่อนว่า toHaveBeenCalled() กำลังพิสูจน์การสื่อสารข้อใด และการเรียกนั้นเป็น contract จริงหรือเป็นเพียงรายละเอียดภายใน
เลือก assertion ให้พอดี
| สถานการณ์ | แนวทาง |
|---|---|
| สนใจว่าถูกเรียกหรือไม่ | toHaveBeenCalled() |
| สนใจจำนวนครั้ง | toHaveBeenCalledTimes(n) |
| สนใจข้อมูลที่ส่ง | toHaveBeenCalledWith(...) |
Mock ไม่ใช่เป้าหมายของ test
เริ่มจาก behavior ของ Task service แล้วค่อยตรวจ interaction ที่จำเป็นต่อ behavior นั้น ถ้าเปลี่ยน implementation แล้วยังรักษา contract ได้ test ไม่ควร fail เพียงเพราะรูปแบบภายในเปลี่ยน
แบบฝึก: ตรวจ interaction
ตรวจว่า completeAndNotify ส่ง event อย่างน้อยหนึ่งครั้ง
งานที่ต้องทำ
- สร้าง notify mock
- เรียก completeAndNotify
- assert ว่า notify ถูกเรียก
ลองทำด้วยตัวเองก่อน แล้วค่อยเปิดเฉลยเพื่อเทียบแนวคิดและรายละเอียด