मैं PHP में इकाई परीक्षण कैसे लिखूं? [बन्द है]


98

मैंने हर जगह पढ़ा है कि वे कितने महान हैं, लेकिन किसी कारण से मुझे यह पता नहीं लग सकता है कि मैं वास्तव में कुछ का परीक्षण करने वाला हूं। शायद कोई उदाहरण कोड का एक टुकड़ा पोस्ट कर सकता है और वे इसका परीक्षण कैसे करेंगे? अगर यह बहुत अधिक परेशानी नहीं है :)


5
संतुलन के लिए, PHP के लिए 2, या 3 यूनिट टेस्टिंग फ्रेमवर्क नहीं हैं - यहाँ एक सूची है: en.wikipedia.org/wiki/List_of_unit_testing_frameworks#PHP
Fenton

जवाबों:


36

एक 3 "फ्रेमवर्क" है, जिसे सीखना आसान है - सिंपल टेस्ट से भी आसान , इसे phpt कहा जाता है।

एक प्राइमर यहां पाया जा सकता है: http://qa.php.net/write-test.php

संपादित करें: बस नमूना कोड के लिए आपके अनुरोध को देखा।

मान लें कि आपके पास lib.php नामक फ़ाइल में निम्नलिखित फ़ंक्शन है :

<?php
function foo($bar)
{
  return $bar;
}
?>

वास्तव में सरल और सीधे आगे, जिस पैरामीटर में आप गुजरते हैं, वह वापस आ जाता है। तो आइए इस फ़ंक्शन के लिए एक परीक्षण देखें, हम परीक्षण फ़ाइल को foo.phpt कहेंगे :

--TEST--
foo() function - A basic test to see if it works. :)
--FILE--
<?php
include 'lib.php'; // might need to adjust path if not in the same dir
$bar = 'Hello World';
var_dump(foo($bar));
?>
--EXPECT--
string(11) "Hello World"

संक्षेप में, हम $barमूल्य के साथ पैरामीटर प्रदान करते हैं "Hello World"और हम var_dump()फ़ंक्शन कॉल की प्रतिक्रिया देते हैं foo()

इस परीक्षण को चलाने के लिए, उपयोग करें: pear run-test path/to/foo.phpt

इसके लिए आपके सिस्टम पर PEAR की एक कार्यशील स्थापना की आवश्यकता होती है, जो अधिकांश परिस्थितियों में बहुत आम है। यदि आपको इसे स्थापित करने की आवश्यकता है, तो मैं उपलब्ध नवीनतम संस्करण को स्थापित करने की सलाह देता हूं। यदि आपको इसे स्थापित करने में मदद चाहिए, तो बेझिझक पूछें (लेकिन ओएस आदि प्रदान करें)।


यह नहीं होना चाहिए run-tests?
धर्मन

31

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


22

आप इसे समायोजित करने के लिए अपनी कोडिंग शैली को बदलकर इकाई परीक्षण को अधिक प्रभावी बना सकते हैं।

मैं Google परीक्षण ब्लॉग ब्राउज़ करने की सलाह देता हूं , विशेष रूप से लेखन परीक्षण योग्य कोड पर पोस्ट ।


7
मुझे लगता है कि आपने एक महान पोस्ट का उल्लेख किया है। 'इकाई परीक्षण बहुत प्रभावी नहीं है' के साथ अपना जवाब शुरू करना लगभग मुझे नीचा दिखाने का कारण बना, हालांकि, एक परीक्षण-अनुकूल होने के नाते ... संभवतः, सकारात्मक तरीके से रीफ़्रेश करने से लोगों को लेख पढ़ने के लिए प्रोत्साहित किया जाएगा।
xtofl

2
@xtofl ने इसे 'सकारात्मकता' को थोड़ा बढ़ाने के लिए संपादित किया :)
icc97

13

मैंने अपना खुद का रोल किया क्योंकि मेरे पास किसी को चीजों को करने का तरीका सीखने का समय नहीं है, इसे लिखने के लिए लगभग 20 मिनट लगे, यहां पोस्ट करने के लिए इसे अनुकूलित करने के लिए 10।

Unittesting मेरे लिए बहुत उपयोगी है।

यह थोड़े लंबा है, लेकिन यह खुद को समझाता है और तल पर एक उदाहरण है।

/**
 * Provides Assertions
 **/
class Assert
{
    public static function AreEqual( $a, $b )
    {
        if ( $a != $b )
        {
            throw new Exception( 'Subjects are not equal.' );
        }
    }
}

/**
 * Provides a loggable entity with information on a test and how it executed
 **/
class TestResult
{
    protected $_testableInstance = null;

    protected $_isSuccess = false;
    public function getSuccess()
    {
        return $this->_isSuccess;
    }

    protected $_output = '';
    public function getOutput()
    {
        return $_output;
    }
    public function setOutput( $value )
    {
        $_output = $value;
    }

    protected $_test = null;
    public function getTest()
    {
        return $this->_test;
    }

    public function getName()
    {
        return $this->_test->getName();
    }
    public function getComment()
    {
        return $this->ParseComment( $this->_test->getDocComment() );
    }

    private function ParseComment( $comment )
    {
        $lines = explode( "\n", $comment );
        for( $i = 0; $i < count( $lines ); $i ++ )
        {
            $lines[$i] = trim( $lines[ $i ] );
        }
        return implode( "\n", $lines );
    }

    protected $_exception = null;
    public function getException()
    {
        return $this->_exception;
    }

    static public function CreateFailure( Testable $object, ReflectionMethod $test, Exception $exception )
    {
        $result = new self();
        $result->_isSuccess = false;
        $result->testableInstance = $object;
        $result->_test = $test;
        $result->_exception = $exception;

        return $result;
    }
    static public function CreateSuccess( Testable $object, ReflectionMethod $test )
    {
        $result = new self();
        $result->_isSuccess = true;
        $result->testableInstance = $object;
        $result->_test = $test;

        return $result;
    }
}

/**
 * Provides a base class to derive tests from
 **/
abstract class Testable
{
    protected $test_log = array();

    /**
     * Logs the result of a test. keeps track of results for later inspection, Overridable to log elsewhere.
     **/
    protected function Log( TestResult $result )
    {
        $this->test_log[] = $result;

        printf( "Test: %s was a %s %s\n"
            ,$result->getName()
            ,$result->getSuccess() ? 'success' : 'failure'
            ,$result->getSuccess() ? '' : sprintf( "\n%s (lines:%d-%d; file:%s)"
                ,$result->getComment()
                ,$result->getTest()->getStartLine()
                ,$result->getTest()->getEndLine()
                ,$result->getTest()->getFileName()
                )
            );

    }
    final public function RunTests()
    {
        $class = new ReflectionClass( $this );
        foreach( $class->GetMethods() as $method )
        {
            $methodname = $method->getName();
            if ( strlen( $methodname ) > 4 && substr( $methodname, 0, 4 ) == 'Test' )
            {
                ob_start();
                try
                {
                    $this->$methodname();
                    $result = TestResult::CreateSuccess( $this, $method );
                }
                catch( Exception $ex )
                {
                    $result = TestResult::CreateFailure( $this, $method, $ex );
                }
                $output = ob_get_clean();
                $result->setOutput( $output );
                $this->Log( $result );
            }
        }
    }
}

/**
 * a simple Test suite with two tests
 **/
class MyTest extends Testable
{
    /**
     * This test is designed to fail
     **/
    public function TestOne()
    {
        Assert::AreEqual( 1, 2 );
    }

    /**
     * This test is designed to succeed
     **/
    public function TestTwo()
    {
        Assert::AreEqual( 1, 1 );
    }
}

// this is how to use it.
$test = new MyTest();
$test->RunTests();

यह आउटपुट:

टेस्ट: टेस्टऑन फेल था 
/ **
* इस परीक्षण को विफल करने के लिए डिज़ाइन किया गया है
** / (लाइनें: 149-152; फ़ाइल: /U//ris/Desktop/Testable.php)
टेस्ट: TestTwo एक सफलता थी 

7

PHPUnit प्राप्त करें। यह इस्तेमाल में बहुत आसान है।

फिर बहुत सरल मुखरता के साथ शुरू करें। इससे पहले कि आप किसी और चीज़ में प्रवेश करें, आप AssertEquals के साथ बहुत कुछ कर सकते हैं। अपने पैरों को गीला करने का यह एक अच्छा तरीका है।

आप पहले भी अपना परीक्षण लिखने का प्रयास कर सकते हैं (क्योंकि आपने अपना प्रश्न TDD टैग दिया है) और फिर अपना कोड लिखें। यदि आपने ऐसा नहीं किया है, तो यह एक आंख खोलने वाला है।

require_once 'ClassYouWantToTest';
require_once 'PHPUnit...blah,blah,whatever';

class ClassYouWantToTest extends PHPUnit...blah,blah,whatever
{
    private $ClassYouWantToTest;

   protected function setUp ()
    {
        parent::setUp();
        $this->ClassYouWantToTest = new ClassYouWantToTest(/* parameters */);
    }

    protected function tearDown ()
    {
        $this->ClassYouWantToTest = null;
        parent::tearDown();
    }

    public function __construct ()
    {   
        // not really needed
    }

    /**
     * Tests ClassYouWantToTest->methodFoo()
     */
    public function testMethodFoo ()
    {
        $this->assertEquals(
            $this->ClassYouWantToTest->methodFoo('putValueOfParamHere), 'expectedOutputHere);

    /**
     * Tests ClassYouWantToTest->methodBar()
     */
    public function testMethodFoo ()
    {
        $this->assertEquals(
            $this->ClassYouWantToTest->methodBar('putValueOfParamHere), 'expectedOutputHere);
}

5

सरल परीक्षणों और प्रलेखन के लिए, php-doctest काफी अच्छा है और इसे शुरू करने का वास्तव में आसान तरीका है क्योंकि आपको एक अलग फाइल नहीं खोलनी है। नीचे दिए गए कार्य की कल्पना करें:

/**
* Sums 2 numbers
* <code>
* //doctest: add
* echo add(5,2);
* //expects:
* 7
* </code>
*/
function add($a,$b){
    return $a + $b;   
}

यदि आप अब इस फ़ाइल को phpdt (php-doctest के कमांड-लाइन धावक) के माध्यम से चलाते हैं, तो 1 परीक्षण चलाया जाएगा। सिद्धांत <कोड> ब्लॉक के अंदर निहित है। सिद्धांत की उत्पत्ति अजगर में हुई है और कोड काम करने के तरीके पर उपयोगी और चल उदाहरण देने के लिए ठीक है। आप इसे विशेष रूप से उपयोग नहीं कर सकते क्योंकि कोड खुद ही परीक्षण मामलों से जूझ जाएगा, लेकिन मैंने पाया है कि यह एक अधिक औपचारिक tdd पुस्तकालय के साथ उपयोगी है - मैं phpunit का उपयोग करता हूं।

यह 1 उत्तर यहाँ अच्छी तरह से गाया जाता है (यह इकाई बनाम सिद्धांत नहीं है)।


1
क्या यह स्रोत को थोड़ा अव्यवस्थित नहीं करता है?
अली घणावतियन

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

2

phpunit php के लिए डिफैक्टो यूनिट टेस्टिंग फ्रेमवर्क बहुत ज्यादा है। इसमें DocTest (PEAR पैकेज के रूप में उपलब्ध) और कुछ अन्य भी हैं। php ही regressions के लिए परीक्षण किया जाता है और phpt परीक्षणों के माध्यम से पसंद किया जाता है जिसे नाशपाती के माध्यम से भी चलाया जा सकता है।


2

कोडेशन टेस्ट आम यूनिट टेस्ट की तरह होते हैं, लेकिन उन चीजों में बहुत शक्तिशाली होते हैं, जहां आपको मॉकिंग और स्टबिंग की जरूरत होती है।

यहाँ नमूना नियंत्रक परीक्षण है। ध्यान दें कि स्टब्स कितनी आसानी से बनते हैं। आप कितनी आसानी से विधि की जांच कर रहे थे।

<?php
use Codeception\Util\Stub as Stub;

const VALID_USER_ID = 1;
const INVALID_USER_ID = 0;

class UserControllerCest {
public $class = 'UserController';


public function show(CodeGuy $I) {
    // prepare environment
    $I->haveFakeClass($controller = Stub::makeEmptyExcept($this->class, 'show'));
    $I->haveFakeClass($db = Stub::make('DbConnector', array('find' => function($id) { return $id == VALID_USER_ID ? new User() : null ))); };
    $I->setProperty($controller, 'db', $db);

    $I->executeTestedMethodOn($controller, VALID_USER_ID)
        ->seeResultEquals(true)
        ->seeMethodInvoked($controller, 'render');

    $I->expect('it will render 404 page for non existent user')
        ->executeTestedMethodOn($controller, INVALID_USER_ID)
        ->seeResultNotEquals(true)
        ->seeMethodInvoked($controller, 'render404','User not found')
        ->seeMethodNotInvoked($controller, 'render');
}
}

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


1

पहले से दिए गए परीक्षण ढाँचों के बारे में उत्कृष्ट सुझावों के अलावा, क्या आप अपने आवेदन को PHP वेब फ्रेमवर्क में से एक के साथ बना रहे हैं जिसमें स्वचालित परीक्षण जैसे कि सिम्फनी या केकपीएचपी बनाया गया है ? कभी-कभी आपके परीक्षण के तरीकों में कमी आने का स्थान होता है, कुछ लोगों को स्वचालित परीक्षण और टीडीडी के साथ शुरू होने वाले घर्षण को कम कर देता है।


1

यहां पुन: पोस्ट करने के लिए बहुत अधिक रास्ता है, लेकिन यहां phpt का उपयोग करने पर एक शानदार लेख है । यह phpt के आस-पास कई पहलुओं को समाहित करता है जिन्हें अक्सर अनदेखा किया जाता है, इसलिए यह सिर्फ एक परीक्षा लिखने से परे php के अपने ज्ञान का विस्तार करने के लिए पढ़ने लायक हो सकता है। सौभाग्य से लेख भी परीक्षण परीक्षण पर चर्चा करता है!

चर्चा के मुख्य बिंदु

  1. पता चलता है कि PHP के काम के मामूली पहलुओं को कैसे दर्ज़ किया गया है (या उस मामले के लिए बहुत ज्यादा हिस्सा)
  2. अपने स्वयं के PHP कोड के लिए सरल इकाई परीक्षण लिखें
  3. विस्तार के हिस्से के रूप में या आंतरिक या क्यूए समूहों को एक संभावित बग को व्यक्त करने के लिए परीक्षण लिखें

1

मुझे पता है कि यहां पहले से ही बहुत सारी जानकारी है, लेकिन चूंकि यह अभी भी Google खोजों पर दिखाता है इसलिए मैं चिनूक टेस्ट सूट को सूची में जोड़ सकता हूं । यह एक सरल और छोटा परीक्षण ढांचा है।

आप आसानी से इसके साथ अपनी कक्षाओं का परीक्षण कर सकते हैं और नकली वस्तुएं भी बना सकते हैं। आप कंसोल के माध्यम से वेब ब्राउज़र और (अभी तक नहीं) के माध्यम से परीक्षण चलाते हैं । ब्राउज़र में आप निर्दिष्ट कर सकते हैं कि कौन सी परीक्षा कक्षा या यहां तक ​​कि कौन सी परीक्षा विधि को चलाना है। या आप बस सभी परीक्षण चला सकते हैं।

जीथब पृष्ठ से एक स्क्रीनशॉट:

चिनूक यूनिट टेस्ट रूपरेखा

मैं इसके बारे में क्या पसंद करता हूं, जिस तरह से आप परीक्षण करते हैं। यह तथाकथित "धाराप्रवाह जोर" के साथ किया जाता है। उदाहरण:

$this->Assert($datetime)->Should()->BeAfter($someDatetime);

और नकली वस्तुओं का निर्माण एक हवा भी है (वाक्य रचना जैसे धाराप्रवाह के साथ):

$mock = new CFMock::Create(new DummyClass());
$mock->ACallTo('SomeMethod')->Returns('some value');

वैसे भी, अधिक जानकारी जीथब पृष्ठ पर कोड उदाहरण के साथ मिल सकती है:

https://github.com/w00/Chinook-TestSuite

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.