0Pricing
PHP Academy · บทเรียน

การทดสอบการกลายพันธุ์ด้วย 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. เวิร์กโฟลว์การพัฒนาโดยขับเคลื่อนด้วยการทดสอบ
  2. การจำลองและการแทนที่ด้วย Mockery
  3. การทดสอบแบบผสานรวมและเชิงฟังก์ชัน
  4. การทดสอบการกลายพันธุ์ด้วย Infection
← กลับไปที่ PHP Academy