PHP में Mutation Testing: ऐसे लिखें टेस्ट जो वास्तव में बग पकड़ें

शुरुआती लोगों के लिए ऑनलाइन Python प्रशिक्षक

Python आसानी से सीखें बिना सिद्धांत के बोझ के। स्वचालित जांच के साथ व्यावहारिक कार्य हल करें और ब्राउज़र में सीधे कोड लिखें।

पाठ्यक्रम शुरू करें

परिचय: 100% कोड कवरेज क्यों एक भ्रम है?

क्या आपने कभी PHPUnit की रिपोर्ट देखकर गर्व महसूस किया जिसमें लिखा हो "Code Coverage: 98%"? और फिर आपने रिलीज़ किया, और प्रोडक्शन में एक गंभीर बग आ गया। परिचित लग रहा है? समस्या यह है कि क्लासिकल कवरेज (line/statement coverage) केवल यह मापता है कि कोड की कौन सी लाइनें execute हुईं। यह यह जाँच नहीं करता कि आपके टेस्ट लॉजिक को चेक कर रहे हैं या नहीं।

कल्पना करें कि आपने एक टेस्ट लिखा जो जाँचता है कि फंक्शन true लौटाता है। और फंक्शन हमेशा true लौटाता है, भले ही वह टूट जाए। टेस्ट पास हो जाएगा, कवरेज 100% होगा, लेकिन आप बग नहीं पकड़ पाएंगे। यहीं पर PHP में mutation testing काम आता है — एक ऐसी तकनीक जो टेस्टिंग के बारे में आपकी सोच को बदल देती है।

इस लेख में हम जानेंगे कि म्यूटेशन टेस्टिंग क्या है, यह रियल PHP कोड के उदाहरणों के साथ कैसे काम करता है, और Infection लाइब्रेरी का उपयोग करके इसे अपने प्रोजेक्ट में कैसे लागू करें।

Mutation Testing क्या है? (और यह कोई जादू क्यों नहीं है)

Mutation testing (या म्यूटेशन टेस्टिंग) टेस्ट की गुणवत्ता का मूल्यांकन करने की एक विधि है, जिसमें सोर्स कोड में छोटे-छोटे जानबूझकर बदलाव (म्यूटेशन) किए जाते हैं। यदि बदलाव के बाद टेस्ट फेल हो जाता है — म्यूटेंट मारा गया, टेस्ट काम कर रहा है। यदि टेस्ट पास रहता है — म्यूटेंट बच गया, यानी आपका टेस्ट कुछ भी जाँच नहीं कर रहा है।

एक सरल उदाहरण: आप एक सुरक्षा गार्ड हैं, और आपके टेस्ट कैमरे हैं। म्यूटेशन टेस्टिंग बिल्डिंग में "बदमाशों" (म्यूटेंट) को भेजता है। यदि कैमरा (टेस्ट) बदमाश को देखता है — वह काम कर रहा है। यदि बदमाश आराम से घूमता रहता है — कैमरा बेकार है।

PHP में इसके लिए मुख्य टूल Infection है — एक लाइब्रेरी जो हर म्यूटेंट पर PHPUnit चलाती है और परिणामों का विश्लेषण करती है।

यह व्यवहार में कैसा दिखता है?

मान लीजिए आपके पास एक सरल कैलकुलेटर क्लास है:

<?php
class Calculator
{
    public function add(int $a, int $b): int
    {
        return $a + $b;
    }
}

और इसका टेस्ट:

<?php
use PHPUnit\\Framework\\TestCase;

class CalculatorTest extends TestCase
{
    public function testAdd()
    {
        $calc = new Calculator();
        $result = $calc->add(2, 3);
        $this->assertEquals(5, $result);
    }
}

Infection टूल एक म्यूटेंट बनाएगा, + को - से बदलकर:

return $a - $b;

फिर टेस्ट चलाएगा। यदि टेस्ट फेल होता है — म्यूटेंट मारा गया। यदि टेस्ट पास होता है (और यह पास होगा क्योंकि आप केवल 2+3 चेक कर रहे हैं, 2-3 नहीं) — म्यूटेंट बच गया। यह एक संकेत है: आपका टेस्ट पर्याप्त अच्छा नहीं है।

Infection की स्थापना और पहला रन

सबसे पहले Composer के माध्यम से Infection इंस्टॉल करें:

composer require --dev infection/infection

फिर एक कॉन्फ़िगरेशन फ़ाइल infection.json बनाएं (या इंटरैक्टिव सेटअप के लिए vendor/bin/infection चलाएं)।

न्यूनतम कॉन्फ़िगरेशन का उदाहरण:

{
    "source": {
        "directories": [
            "src"
        ]
    },
    "phpUnit": {
        "configDir": "."
    },
    "mutators": {
        "@default": true
    }
}

म्यूटेशन टेस्टिंग चलाएं:

vendor/bin/infection --min-msi=100

जहाँ --min-msi=100 का मतलब है कि हम चाहते हैं कि 100% म्यूटेंट मारे जाएं (आदर्श, लेकिन शायद ही कभी प्राप्त होता है)। Infection HTML फॉर्मेट में एक रिपोर्ट बनाएगा (फ़ोल्डर infection.html), जहाँ बचे हुए म्यूटेंट लाल रंग में चिह्नित होंगे।

PHP में म्यूटेशन के प्रकार (उदाहरण सहित)

Infection दर्जनों म्यूटेटर सपोर्ट करता है। यहाँ सबसे सामान्य हैं जिनका आप सामना करेंगे:

1. गणितीय ऑपरेटर

+ को -, * को /, % को * आदि से बदलना।

// मूल कोड
return $price * $quantity;

// म्यूटेंट
return $price / $quantity;

ब्लॉग

पुस्तक अनुशंसाएँ