खोज…


वाक्य - विन्यास

टिप्पणियों

Unit कोड का उपयोग स्रोत कोड के परीक्षण के लिए किया जाता है ताकि यह देखा जा सके कि इसमें इनपुट्स के साथ सौदे हैं या नहीं। Unit परीक्षणों को बहुसंख्यक चौखटे द्वारा समर्थित किया जाता है। कई अलग-अलग PHPUnit परीक्षण हैं और वे सिंटैक्स में भिन्न हो सकते हैं। इस उदाहरण में हम PHPUnit का उपयोग कर रहे हैं।

परीक्षण नियम

मान लीजिए, हमारे पास नियमों () विधि के साथ एक सरल LoginForm वर्ग है (फ्रेमवर्क टेम्पलेट के रूप में लॉगिन पृष्ठ में उपयोग किया जाता है):

class LoginForm {
    public $email;
    public $rememberMe;
    public $password;

    /* rules() method returns an array with what each field has as a requirement.
     * Login form uses email and password to authenticate user.
     */
    public function rules() {
        return [
            // Email and Password are both required
            [['email', 'password'], 'required'],

            // Email must be in email format
            ['email', 'email'],

            // rememberMe must be a boolean value
            ['rememberMe', 'boolean'],

            // Password must match this pattern (must contain only letters and numbers)
            ['password', 'match', 'pattern' => '/^[a-z0-9]+$/i'],
        ];
    }

    /** the validate function checks for correctness of the passed rules */
    public function validate($rule) {
        $success = true;
        list($var, $type) = $rule;
        foreach ((array) $var as $var) {
            switch ($type) {
                case "required":
                    $success = $success && $this->$var != "";
                    break;
                case "email":
                    $success = $success && filter_var($this->$var, FILTER_VALIDATE_EMAIL);
                    break;
                case "boolean":
                    $success = $success && filter_var($this->$var, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) !== null;
                    break;
                case "match":
                    $success = $success && preg_match($rule["pattern"], $this->$var);
                    break;
                default:
                    throw new \InvalidArgumentException("Invalid filter type passed")
            }
        }
        return $success;
    }
}

इस वर्ग पर परीक्षण करने के लिए, हम यूनिट परीक्षण का उपयोग करते हैं (यह जानने के लिए कि क्या यह हमारी उम्मीदों पर खरा उतरता है) देखने के लिए स्रोत कोड की जाँच करें:

class LoginFormTest extends TestCase {
    protected $loginForm;

    // Executing code on the start of the test
    public function setUp() {
        $this->loginForm = new LoginForm;
    }

    // To validate our rules, we should use the validate() method

    /**
     * This method belongs to Unit test class LoginFormTest and
     * it's testing rules that are described above.
     */
    public function testRuleValidation() {
        $rules = $this->loginForm->rules();

        // Initialize to valid and test this
        $this->loginForm->email = "[email protected]";
        $this->loginForm->password = "password";
        $this->loginForm->rememberMe = true;
        $this->assertTrue($this->loginForm->validate($rules), "Should be valid as nothing is invalid");

        // Test email validation
        // Since we made email to be in email format, it cannot be empty
        $this->loginForm->email = '';
        $this->assertFalse($this->loginForm->validate($rules), "Email should not be valid (empty)");

        // It does not contain "@" in string so it's invalid
        $this->loginForm->email = 'invalid.email.com';
        $this->assertFalse($this->loginForm->validate($rules), "Email should not be valid (invalid format)");

        // Revert email to valid for next test
        $this->loginForm->email = '[email protected]';

        // Test password validation
        // Password cannot be empty (since it's required)
        $this->loginForm->password = '';
        $this->assertFalse($this->loginForm->validate($rules), "Password should not be valid (empty)");

        // Revert password to valid for next test
        $this->loginForm->password = 'ThisIsMyPassword';

        // Test rememberMe validation
        $this->loginForm->rememberMe = 999;
        $this->assertFalse($this->loginForm->validate($rules), "RememberMe should not be valid (integer type)");

        // Revert remeberMe to valid for next test
        $this->loginForm->rememberMe = true;
    }
}

यहाँ वास्तव में Unit परीक्षण (सामान्य उदाहरणों को छोड़कर) के साथ कैसे मदद कर सकते हैं? उदाहरण के लिए, यह बहुत अच्छी तरह से फिट बैठता है जब हम अप्रत्याशित परिणाम प्राप्त करते हैं। उदाहरण के लिए, आइए पहले से यह नियम लें:

['password', 'match', 'pattern' => '/^[a-z0-9]+$/i'],

इसके बजाय, अगर हम एक महत्वपूर्ण बात याद करते हैं और यह लिखते हैं:

['password', 'match', 'pattern' => '/^[a-z0-9]$/i'],

दर्जनों विभिन्न नियमों के साथ (यह मानते हुए कि हम केवल ईमेल और पासवर्ड का उपयोग नहीं कर रहे हैं), गलतियों का पता लगाना मुश्किल है। यह इकाई परीक्षण:

// Initialize to valid and test this
$this->loginForm->email = "[email protected]";
$this->loginForm->password = "password";
$this->loginForm->rememberMe = true;
$this->assertTrue($this->loginForm->validate($rules), "Should be valid as nothing is invalid");

हमारे पहले उदाहरण को पारित करेंगे लेकिन दूसरे को नहीं। क्यों? क्योंकि दूसरे उदाहरण में हमने टाइपो (मिस्ड + साइन) के साथ एक पैटर्न लिखा है, जिसका अर्थ है कि यह केवल एक अक्षर / संख्या को स्वीकार करता है।

यूनिट टेस्ट कमांड के साथ कंसोल में चलाए जा सकते हैं: phpunit [path_to_file] । यदि सब कुछ ठीक है, तो हमें यह देखने में सक्षम होना चाहिए कि सभी परीक्षण OK स्थिति में हैं, अन्यथा हम या तो Error (सिंटैक्स त्रुटियां) या Fail देखेंगे (उस पद्धति में कम से कम एक पंक्ति पास नहीं हुई)।

अतिरिक्त मापदंडों जैसे --coverage हम यह भी देख सकते हैं कि बैकएंड कोड में कितनी लाइनों का परीक्षण किया गया था और जो पारित / असफल हो गया था। यह किसी भी ढांचे पर लागू होता है जिसने PHPUnit स्थापित किया है।

उदाहरण के लिए कैसे PHPUnit परीक्षण सांत्वना में दिखता है (सामान्य रूप, इस उदाहरण के अनुसार नहीं):

यहाँ छवि विवरण दर्ज करें

PHPUnit डेटा प्रदाता

परीक्षण विधियों को अक्सर परीक्षण के साथ डेटा की आवश्यकता होती है। पूरी तरह से कुछ तरीकों का परीक्षण करने के लिए आपको हर संभव परीक्षण स्थिति के लिए अलग-अलग डेटा सेट प्रदान करने की आवश्यकता होती है। बेशक, आप इसे लूप्स का उपयोग करके मैन्युअल रूप से कर सकते हैं, जैसे:

...
public function testSomething()
{
    $data = [...];
    foreach($data as $dataSet) {
       $this->assertSomething($dataSet);
    }
}
... 

और कोई इसे सुविधाजनक पा सकता है। लेकिन इस दृष्टिकोण की कुछ कमियां हैं। यदि आपका परीक्षण फ़ंक्शन कई मापदंडों को स्वीकार करता है तो सबसे पहले, आपको डेटा निकालने के लिए अतिरिक्त क्रियाएं करनी होंगी। दूसरा, विफलता पर अतिरिक्त संदेशों और डिबगिंग के बिना सेट किए गए असफल डेटा को अलग करना मुश्किल होगा। तीसरा, PHPUnit डेटा प्रदाताओं का उपयोग करके परीक्षण डेटा सेट से निपटने के लिए स्वचालित तरीका प्रदान करता है।

डेटा प्रदाता एक फ़ंक्शन है, जिसे आपके विशेष परीक्षण मामले के लिए डेटा वापस करना चाहिए।

एक डेटा प्रदाता विधि सार्वजनिक होनी चाहिए और या तो सरणियों या किसी ऑब्जेक्ट को वापस करना चाहिए जो Iterator इंटरफ़ेस को लागू करता है और प्रत्येक पुनरावृत्ति चरण के लिए एक सरणी देता है। प्रत्येक सरणी के लिए जो संग्रह का हिस्सा है, परीक्षण विधि को उसके तर्कों के रूप में सरणी की सामग्री के साथ बुलाया जाएगा।

अपने परीक्षण के साथ एक डेटा प्रदाता का उपयोग करने के लिए, निर्दिष्ट डेटा प्रदाता फ़ंक्शन के नाम के साथ @dataProvider एनोटेशन का उपयोग करें:

/**
* @dataProvider dataProviderForTest
*/
public function testEquals($a, $b)
{
    $this->assertEquals($a, $b);
}

public function dataProviderForTest()
{
    return [
        [1,1],
        [2,2],
        [3,2] //this will fail
    ];
}

सरणियों का सरणी

ध्यान दें कि dataProviderForTest() सरणी का रिटर्न देता है। प्रत्येक नेस्टेड सरणी में दो तत्व होते हैं और वे एक-एक करके testEquals() लिए आवश्यक पैरामीटर testEquals() । इस तरह की त्रुटि Missing argument 2 for Test::testEquals() फेंक दिया जाएगा यदि पर्याप्त तत्व नहीं हैं। PHPUnit स्वचालित रूप से डेटा और रन टेस्ट के माध्यम से लूप करेगा:

public function dataProviderForTest()
{
    return [
        [1,1], // [0] testEquals($a = 1, $b = 1)
        [2,2], // [1] testEquals($a = 2, $b = 2)
        [3,2]  // [2] There was 1 failure: 1) Test::testEquals with data set #2 (3, 4)
    ];
}

प्रत्येक डेटा सेट को सुविधा के लिए नामित किया जा सकता है। असफल डेटा का पता लगाना आसान होगा:

public function dataProviderForTest()
{
    return [
        'Test 1' => [1,1], // [0] testEquals($a = 1, $b = 1)
        'Test 2' => [2,2], // [1] testEquals($a = 2, $b = 2)
        'Test 3' => [3,2]  // [2] There was 1 failure: 
                           //     1) Test::testEquals with data set "Test 3" (3, 4)
    ];
}

iterators

class MyIterator implements Iterator {
    protected $array = [];

    public function __construct($array) {
        $this->array = $array;
    }

    function rewind() {
        return reset($this->array);
    }

    function current() {
        return current($this->array);
    }

    function key() {
        return key($this->array);
    }

    function next() {
        return next($this->array);
    }

    function valid() {
        return key($this->array) !== null;
    }
}
...

class Test extends TestCase
{
    /**
     * @dataProvider dataProviderForTest
     */
    public function testEquals($a)
    {
        $toCompare = 0;

        $this->assertEquals($a, $toCompare);
    }

    public function dataProviderForTest()
    {
        return new MyIterator([
            'Test 1' => [0],
            'Test 2' => [false],
            'Test 3' => [null]
        ]);
    }
}

जैसा कि आप देख सकते हैं, सरल पुनरावृत्त भी काम करता है।

ध्यान दें कि एकल पैरामीटर के लिए भी, डेटा प्रदाता को एक सरणी [$parameter] वापस करनी होगी

क्योंकि यदि हम अपनी current() विधि (जो वास्तव में हर पुनरावृत्ति पर डेटा लौटाते हैं current() बदल देते हैं:

function current() {
    return current($this->array)[0];
}

या वास्तविक डेटा बदलें:

return new MyIterator([
            'Test 1' => 0,
            'Test 2' => false,
            'Test 3' => null
        ]);

हमें एक त्रुटि मिलेगी:

There was 1 warning:

1) Warning
The data provider specified for Test::testEquals is invalid.

बेशक, एक साधारण सरणी पर Iterator ऑब्जेक्ट का उपयोग करना उपयोगी नहीं है। इसे आपके मामले के लिए कुछ विशिष्ट तर्क को लागू करना चाहिए।

जेनरेटर

यह स्पष्ट रूप से नोट नहीं किया गया है और मैनुअल में दिखाया गया है, लेकिन आप डेटा प्रदाता के रूप में एक जनरेटर का उपयोग भी कर सकते हैं। ध्यान दें कि Generator वर्ग वास्तव में Iterator इंटरफ़ेस लागू करता है।

तो यहाँ generator के साथ DirectoryIterator का उपयोग करने का एक उदाहरण है:

/**
 * @param string $file
 *
 * @dataProvider fileDataProvider
 */
public function testSomethingWithFiles($fileName)
{
    //$fileName is available here
    
    //do test here
}

public function fileDataProvider()
{
    $directory = new DirectoryIterator('path-to-the-directory');

    foreach ($directory as $file) {
        if ($file->isFile() && $file->isReadable()) {
            yield [$file->getPathname()]; // invoke generator here.
        }
    }
}

नोट प्रदाता yield एक सरणी है। आपको इसके बजाय एक अमान्य डेटा-प्रदाता चेतावनी मिलेगी।

अपवादों का परीक्षण करें

मान लें कि आप परीक्षण विधि चाहते हैं जो एक अपवाद फेंकता है

class Car
{
    /**
     * @throws \Exception
     */
    public function drive()
    {
        throw new \Exception('Useful message', 1);
    }
}

आप ऐसा कर सकते हैं कि विधि कॉल को एक कोशिश / कैच ब्लॉक में सम्मिलित करके और निष्पादन ऑब्जेक्ट की संपत्तियों पर जोर देकर, लेकिन अधिक आसानी से आप अपवाद के तरीकों का उपयोग कर सकते हैं। PHPUnit 5.2 के अनुसार, आपके पास अपवाद प्रकार, संदेश और कोड को सम्मिलित करने के लिए अपेक्सएक्स () विधियाँ उपलब्ध हैं

class DriveTest extends PHPUnit_Framework_TestCase
{
    public function testDrive()
    {
        // prepare
        $car = new \Car();
        $expectedClass = \Exception::class;
        $expectedMessage = 'Useful message';
        $expectedCode = 1;

        // test
        $this->expectException($expectedClass);
        $this->expectMessage($expectedMessage);
        $this->expectCode($expectedCode);

        // invoke
        $car->drive();
    }
}

यदि आप PHPUnit के पुराने संस्करण का उपयोग कर रहे हैं, तो विधि setExpectedException का उपयोग अपेक्षानुसार xx () विधियों से किया जा सकता है, लेकिन ध्यान रखें कि यह पदावनत है और संस्करण 6 में हटा दी जाएगी।

class DriveTest extends PHPUnit_Framework_TestCase
{
    public function testDrive()
    {
        // prepare
        $car = new \Car();
        $expectedClass = \Exception::class;
        $expectedMessage = 'Useful message';
        $expectedCode = 1;

        // test
        $this->setExpectedException($expectedClass, $expectedMessage, $expectedCode);

        // invoke
        $car->drive();
    }
}


Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow