การทดสอบการกลายพันธุ์ด้วย Infection
วัดว่าการทดสอบของคุณมีคุณภาพจริงเพียงใด
การทดสอบการกลายพันธุ์ด้วย Infection เป็นบทเรียน PHP Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน PHP Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส PHP Academy มีบทเรียนทั้งหมด 4 บทเรียน
ความครอบคลุมไม่ได้บอกความจริง
ความครอบคลุมระดับบรรทัด 100% ให้ความรู้สึกน่าอุ่นใจ แต่พิสูจน์ได้เพียงว่าการทดสอบของคุณ เรียกใช้ โค้ดแล้ว ไม่ได้พิสูจน์ว่าจะ ตรวจพบข้อผิดพลาด ในโค้ดนั้น การทดสอบอาจเรียกใช้บรรทัดหนึ่งแล้วไม่ได้ตรวจสอบสิ่งที่มีความหมายเลย การทดสอบการกลายพันธุ์ วัดสิ่งที่สำคัญจริง นั่นคือ หากโค้ดถูกทำให้ผิดพลาดเล็กน้อย การทดสอบของคุณจะล้มเหลวหรือไม่ Infection เป็นเครื่องมือ PHP มาตรฐานสำหรับงานนี้
composer require --dev infection/infectionแนวคิดหลัก: มิวแทนต์
Infection นำโค้ดที่มีความครอบคลุมแล้วใส่ข้อผิดพลาดเล็ก ๆ เข้าไป เรียกว่า มิวแทนต์ โดยเปลี่ยน > เป็น >= เปลี่ยน + เป็น - เปลี่ยน && เป็น || ลบ return และอื่น ๆ จากนั้นจะเรียกใช้การทดสอบของคุณซ้ำกับมิวแทนต์แต่ละตัว:
- หากการทดสอบ ล้มเหลว → มิวแทนต์ถูก กำจัด (ดี เพราะการทดสอบตรวจพบข้อผิดพลาด)
- หากการทดสอบทั้งหมด ผ่าน → มิวแทนต์ รอด (ไม่ดี เพราะข้อผิดพลาดจริงในจุดนี้อาจไม่มีใครตรวจพบ)
ตัวอย่างมิวแทนต์ที่รอด
ลองพิจารณาฟังก์ชันนี้กับการทดสอบที่ไม่รัดกุม Infection จะเปลี่ยน >= เป็น > หากไม่มีการทดสอบใดตรวจสอบขอบเขตที่แน่นอน เช่น จำนวนเงินเท่ากับเกณฑ์ มิวแทนต์นั้นจะรอด ซึ่งเผยให้เห็นกรณีขอบที่ยังไม่ได้ทดสอบ
<?php
function qualifiesForFreeShipping(float $total): bool
{
return $total >= 50.0; // Infection mutates >= to >
}
// Weak test only checks 100 and 10 -> never tests exactly 50.0
var_dump(qualifiesForFreeShipping(100.0)); // true
var_dump(qualifiesForFreeShipping(10.0)); // false
var_dump(qualifiesForFreeShipping(50.0)); // true <-- the boundary the mutant exposes
กำจัดมิวแทนต์
เพิ่มการตรวจสอบขอบเขต แล้วมิวแทนต์ >=-เป็น-> จะถูกกำจัด ภายใต้โค้ดที่ถูกกลายพันธุ์ 50.0 > 50.0 จะมีค่าเป็น false ดังนั้นการทดสอบจึงล้มเหลว ซึ่งตรงกับสิ่งที่เราต้องการ การทดสอบการกลายพันธุ์จะบอกคุณโดยตรงว่าขาดการตรวจสอบใดอยู่
<?php
use PHPUnit\Framework\TestCase;
final class ShippingTest extends TestCase
{
public function test_threshold_is_inclusive(): void
{
// Kills the >= -> > mutant
self::assertTrue(qualifiesForFreeShipping(50.0));
}
}
การกำหนดค่า: infection.json
Infection ทำงานโดยใช้ infection.json5 คุณต้องประกาศว่าจะกลายพันธุ์ไดเรกทอรีใด จะบันทึกบันทึกการทำงานไว้ที่ไหน และกำหนดเกณฑ์คะแนนขั้นต่ำสำหรับให้ CI ผ่าน ให้ source.directories ชี้ไปยังโค้ดสำหรับใช้งานจริงเท่านั้น ไม่ใช่การทดสอบของคุณ
{
"source": {
"directories": ["src"]
},
"logs": {
"text": "build/infection.log",
"html": "build/infection.html"
},
"mutators": {
"@default": true
},
"minMsi": 80,
"minCoveredMsi": 90
}ตัวชี้วัด MSI
Infection รายงาน ตัวชี้วัดคะแนนการกลายพันธุ์:
- MSI = มิวแทนต์ที่ถูกกำจัด / มิวแทนต์ทั้งหมด โดยมีมิวแทนต์จากโค้ดที่ไม่มีความครอบคลุมเป็นตัวลดคะแนน เพราะมิวแทนต์เหล่านั้นไม่สามารถถูกกำจัดได้
- MSI ของส่วนที่ครอบคลุม = มิวแทนต์ที่ถูกกำจัด / มิวแทนต์บนบรรทัดที่มีความครอบคลุม ใช้วัดว่าการตรวจสอบของคุณดีเพียงใดในส่วนที่คุณทดสอบจริง
- ความครอบคลุมโค้ดจากการกลายพันธุ์ = ปริมาณโค้ดที่ Infection สามารถกลายพันธุ์ได้ทั้งหมด
ความครอบคลุมระดับบรรทัดสูงแต่ MSI ของส่วนที่ครอบคลุมต่ำ เป็นสัญญาณคลาสสิกของการทดสอบที่มีการตรวจสอบไม่เพียงพอ
เรียกใช้ Infection อย่างมีประสิทธิภาพ
การทดสอบการกลายพันธุ์ใช้ทรัพยากรมาก เพราะต้องเรียกใช้ชุดการทดสอบซ้ำหนึ่งครั้งต่อมิวแทนต์ วิธีเพิ่มความเร็วที่สำคัญมีสองอย่าง คือเรียกใช้การทดสอบแบบขนานด้วย --threads และกลายพันธุ์เฉพาะโค้ดที่สาขาปัจจุบันมีการแก้ไข โดยใช้การกรองผลต่างของ Git ซึ่งเหมาะอย่างยิ่งสำหรับ CI บนคำขอผสานโค้ด
vendor/bin/infection --threads=max --git-diff-lines --git-diff-base=origin/mainอ่านมิวแทนต์ที่รอด
คุณค่าที่แท้จริงอยู่ในผลต่างที่ Infection แสดงสำหรับมิวแทนต์แต่ละตัวที่รอด ผลดังกล่าวจะแสดงบรรทัดที่แน่นอนและการเปลี่ยนแปลงที่การทดสอบของคุณตรวจไม่พบ ให้ถือว่ามิวแทนต์ที่รอดเป็นรายการงานค้าง โดยเพิ่มการตรวจสอบที่ขาดหายไป หรือยอมรับว่ามิวแทนต์นั้นไม่เป็นอันตราย (เป็นมิวแทนต์ที่เทียบเท่า)
- return $total >= 50.0;
+ return $total > 50.0;
# Mutant survived: no test asserts the inclusive boundary (total === 50.0)มิวแทนต์ที่เทียบเท่าและการละเว้น
มิวแทนต์บางตัว เทียบเท่า กัน กล่าวคือ มิวแทนต์เปลี่ยนโค้ดแต่ไม่เปลี่ยนพฤติกรรมที่สังเกตได้ ดังนั้นจึงไม่มีการทดสอบใดกำจัดมันได้ มิวแทนต์เหล่านี้ไม่สามารถถูกกำจัด และทำให้ MSI ลดลงอย่างไม่เป็นธรรม ควรปิดใช้งานตัวกลายพันธุ์ที่ทราบว่าให้ผลบวกลวงเฉพาะจุดในโค้ด แทนการปรับการทดสอบเพื่อไล่ตามมิวแทนต์เหล่านี้
{
"mutators": {
"@default": true,
"Plus": {
"ignore": ["App\\Math\\Statistics::variance"]
}
}
}จุดที่การทดสอบการกลายพันธุ์ให้ประโยชน์
เนื่องจากการทดสอบนี้ทำงานช้า จึงควรเลือกใช้ให้เหมาะสม:
- ใช้กับ ตรรกะโดเมนหลัก เช่น การกำหนดราคา สิทธิ์ และการคำนวณ ซึ่งข้อผิดพลาดที่ไม่แสดงอาการอาจมีต้นทุนสูง
- กำหนดให้คำขอผสานโค้ดผ่านเกณฑ์โดยดูจาก MSI ของส่วนที่ครอบคลุมในบรรทัดที่เปลี่ยนแปลง ไม่ใช่ทั้งคลังโค้ด
- อย่าพยายามให้ได้ 100% ทั้งระบบ เพราะผลตอบแทนที่ลดลงและมิวแทนต์ที่เทียบเท่าทำให้ความพยายามนั้นสิ้นเปลือง
- ใช้การทดสอบนี้เพื่อ ค้นหาการตรวจสอบที่ไม่รัดกุม แล้วแก้ไขการทดสอบ คะแนนเป็นเพียงเครื่องมือ ไม่ใช่เป้าหมาย
ต้องใช้ข้อมูลความครอบคลุมเพื่อให้ทำงานเร็ว
Infection จะกลายพันธุ์เฉพาะบรรทัดที่การทดสอบของคุณเรียกใช้จริง จึงนำข้อมูลความครอบคลุมจากตัวเรียกใช้การทดสอบกลับมาใช้ หากใช้ Xdebug จะทำงานช้า แต่ pcov เร็วกว่ามากสำหรับความครอบคลุมระดับบรรทัด และเป็นไดรเวอร์ที่แนะนำสำหรับการเรียกใช้การกลายพันธุ์ Infection ยังสามารถสร้างความครอบคลุมเอง หรือรับรายงานความครอบคลุมที่คุณสร้างไว้แล้วใน CI ได้ด้วย
# Faster mutation runs: use pcov instead of Xdebug for coverage
php -d pcov.enabled=1 vendor/bin/infection --threads=max
# Or reuse coverage already generated by your PHPUnit step:
vendor/bin/infection --coverage=build/coverage --skip-initial-testsตรวจสอบอย่างรวดเร็ว
มิวแทนต์ที่รอดบอกอะไรคุณ
สรุปทบทวน
คุณได้เรียนรู้การวัด คุณภาพ ของการทดสอบ ไม่ใช่แค่ปริมาณ:
- การทดสอบการกลายพันธุ์ใส่ข้อผิดพลาดเล็ก ๆ เข้าไป (มิวแทนต์) มิวแทนต์ที่ถูกกำจัดหมายถึงตรวจพบข้อผิดพลาด ส่วนมิวแทนต์ที่รอดหมายถึงมีช่องว่าง
- ความครอบคลุมแสดงการเรียกใช้โค้ด ส่วน MSI ของส่วนที่ครอบคลุมแสดงความแข็งแรงของการตรวจสอบ
- กำหนดค่าผ่าน
infection.json5ด้วยเกณฑ์ MSI และเรียกใช้ด้วย--threadsรวมถึงการกรองผลต่างของ Git เพื่อเพิ่มความเร็ว - มิวแทนต์ที่รอดคือรายการงานค้าง ควรระวังมิวแทนต์ที่เทียบเท่าและละเว้นมิวแทนต์เหล่านั้นอย่างมีเหตุผล
- มุ่งเน้นตรรกะหลัก และกำหนดเกณฑ์คำขอผสานโค้ดจาก MSI ของบรรทัดที่เปลี่ยนแปลง แทนการไล่ตาม 100% ทั้งระบบ
คำถามที่พบบ่อย
บทเรียน “การทดสอบการกลายพันธุ์ด้วย Infection” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การทดสอบการกลายพันธุ์ด้วย Infection” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส PHP Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส PHP Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การทดสอบการกลายพันธุ์ด้วย Infection”
วัดว่าการทดสอบของคุณมีคุณภาพจริงเพียงใด คุณปฏิบัติ PHP Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน PHP Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน PHP Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน
บทเรียน “การทดสอบการกลายพันธุ์ด้วย Infection” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน PHP Academy นี้ได้ไหม
ได้ บทเรียน PHP Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- เวิร์กโฟลว์การพัฒนาโดยขับเคลื่อนด้วยการทดสอบ
- การจำลองและการแทนที่ด้วย Mockery
- การทดสอบแบบผสานรวมและเชิงฟังก์ชัน
- การทดสอบการกลายพันธุ์ด้วย Infection