Mutation Testing สำหรับโค้ดที่เขียนโดย Agent
ชุดการทดสอบที่สร้างโดย LLM อาจมีค่า line และ branch coverage สูงถึง 100% แต่ผลการศึกษาล่าสุดพบว่าพวกมันทำคะแนนได้เพียง 4% ในการทำ Mutation Testing ซึ่งเผยให้เห็นถึงช่องว่างด้านความน่าเชื่อถือที่นักพัฒนาอาจมองข้ามไปในช่วงการรีวิวสปรินต์ (sprint reviews)
นักวิจัยได้ประเมินชุดการทดสอบที่สร้างโดย coding agents ของโมเดลภาษาขนาดใหญ่ (large-language-model) บนเกณฑ์มาตรฐาน HumanEval-Java โดยพบว่าชุดการทดสอบหนึ่งสามารถครอบคลุมโค้ดทุกบรรทัดและทดสอบทุกเงื่อนไข (conditional branch) ได้ครบถ้วน แต่เมื่อชุดการทดสอบเดียวกันนี้ต้องเผชิญกับการทำ Mutation Testing ซึ่งเป็นเทคนิคการฉีดข้อผิดพลาดเล็กๆ น้อยๆ เข้าไปเพื่อดูว่าการทดสอบจะตรวจพบหรือไม่ กลับพบว่ามันตรวจจับบั๊กที่ถูกฉีดเข้าไปได้เพียงส่วนน้อยเท่านั้น
Coverage ดูดี แต่ความหมายที่แท้จริงคืออะไร?
ตัวชี้วัด coverage แบบดั้งเดิมจะนับว่าการทดสอบนั้นรันคำสั่ง (statements) หรือเงื่อนไข (branches) ไปมากน้อยเพียงใด ทีมพัฒนาต่างๆ มักจะชอบตัวเลขที่ดูดีเหล่านี้ในการสาธิตสปรินต์ (sprint demos) อย่างไรก็ตาม ตัวชี้วัดนี้ไม่ได้บอกอะไรเลยว่าการทดสอบจะล้มเหลวหรือไม่หากโค้ดนั้นผิดพลาด Mutation Testing จึงเข้ามาเติมเต็มช่องว่างนี้ด้วยการจงใจสร้างข้อผิดพลาด (mutants) ขึ้นมา และวัดเปอร์เซ็นต์ของ mutants เหล่านั้นที่ทำให้การทดสอบล้มเหลว ซึ่งก็คือ "mutation score" นั่นเอง
ในการศึกษานี้ ชุดการทดสอบที่มี coverage 100% กลับพลาดการตรวจจับ mutants เกือบทั้งหมด รวมถึงข้อผิดพลาดทางตรรกะที่เรียบง่าย เช่น การจัดการวันที่ในปีอธิกสุรทิน (leap-year) ที่ผิดพลาด คะแนน mutation score ที่ 4% หมายความว่าชุดการทดสอบนี้จะตรวจพบเพียงบั๊กจริงๆ เพียงไม่กี่รายการเท่านั้น
ทำไมเรื่องนี้จึงสำคัญต่อการพัฒนาโดยใช้ AI ช่วยเหลือ
- ความมั่นใจที่ผิดพลาด (False confidence): นักพัฒนาอาจเชื่อมั่นในชุดการทดสอบที่ดูสมบูรณ์แบบบนหน้ากระดาษ
- ข้อบกพร่องที่ซ่อนอยู่ (Hidden defects): บั๊กจำนวนมากอาจหลุดรอดไปโดยไม่ถูกสังเกตเห็น
- ต้นทุนในการแก้ไข (Remediation cost): การแก้ไขบั๊กในภายหลังมีต้นทุนสูงกว่าการตรวจพบตั้งแต่เนิ่นๆ มาก
มุมมองต่าง: Coverage ไม่ได้ไร้ประโยชน์
Coverage ยังคงบอกคุณได้ว่าเส้นทางการทำงานของโค้ด (code paths) ถูกรันหรือไม่ แต่มันไม่ได้การันตีว่าจะตรวจพบข้อผิดพลาดได้เสมอไป
สิ่งที่ควรจับตามองต่อไป
- การรวมเข้ากับเครื่องมือ (Tooling integration): ฝัง Mutation Testing เข้าไปใน CI pipelines
- การปรับปรุง LLM: ฝึกฝน agents ให้สร้างการทดสอบที่สามารถ "ฆ่า" mutants ได้
- แนวทางปฏิบัติในอุตสาหกรรม: นำมาตรฐานที่ใช้คู่กันระหว่าง coverage และ mutation scores มาปรับใช้
บทสรุป: ตัวเลข coverage ที่สูงจากการทดสอบที่สร้างโดย AI ไม่ใช่ข้อพิสูจน์ของคุณภาพที่เพียงพออีกต่อไป คะแนน mutation score ที่ต่ำเป็นสัญญาณบ่งบอกว่าการทดสอบอาจไม่สามารถตรวจพบบั๊กที่เกิดขึ้นจริง ซึ่งเป็นการกระตุ้นให้นักพัฒนาควรนำ Mutation Testing มาใช้เป็นตาข่ายรองรับความปลอดภัย (safety net)
