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