मैं पैरामीटर के आधार पर विभिन्न मूल्यों को वापस करने के लिए PHPUnit MockObjects कैसे प्राप्त कर सकता हूं?


141

मुझे एक PHPUnit नकली वस्तु मिली 'return value'है जो इसके तर्क से कोई फर्क नहीं पड़ता:

// From inside a test...
$mock = $this->getMock('myObject', 'methodToMock');
$mock->expects($this->any))
     ->method('methodToMock')
     ->will($this->returnValue('return value'));

मैं जो करने में सक्षम होना चाहता हूं, वह मॉक विधि को पारित किए गए तर्कों के आधार पर एक अलग मूल्य वापस करना है। मैंने कुछ इस तरह की कोशिश की है:

$mock = $this->getMock('myObject', 'methodToMock');

// methodToMock('one')
$mock->expects($this->any))
     ->method('methodToMock')
     ->with($this->equalTo('one'))
     ->will($this->returnValue('method called with argument "one"'));

// methodToMock('two')
$mock->expects($this->any))
     ->method('methodToMock')
     ->with($this->equalTo('two'))
     ->will($this->returnValue('method called with argument "two"'));

लेकिन यह PHPUnit को शिकायत करने का कारण बनता है यदि मॉक को तर्क के साथ नहीं बुलाया जाता है 'two', तो मैं मानता हूं कि परिभाषा पहले की परिभाषा को methodToMock('two')ओवरराइट करती है।

तो मेरा सवाल यह है कि क्या इसके तर्कों के आधार पर PHPUnit नकली वस्तु प्राप्त करने का कोई तरीका है? और यदि हां, तो कैसे?

जवाबों:


125

एक कॉलबैक का उपयोग करें। उदाहरण के लिए (PHPUnit प्रलेखन से सीधे):

<?php
class StubTest extends PHPUnit_Framework_TestCase
{
    public function testReturnCallbackStub()
    {
        $stub = $this->getMock(
          'SomeClass', array('doSomething')
        );

        $stub->expects($this->any())
             ->method('doSomething')
             ->will($this->returnCallback('callback'));

        // $stub->doSomething() returns callback(...)
    }
}

function callback() {
    $args = func_get_args();
    // ...
}
?>

कॉलबैक () में आप जो भी प्रोसेसिंग चाहते हैं, करें और उचित रूप में अपने $ args के आधार पर परिणाम लौटाएं।


2
क्या आप प्रलेखन के लिए एक लिंक प्रदान कर सकते हैं? मैं इसे "Google"
क्रिस एरिकसन

6
ध्यान दें कि आप एक सरणी, उदाहरण के लिए, कॉलबैक के रूप में एक विधि का उपयोग कर सकते हैं $this->returnCallback(array('MyClassTest','myCallback'))
पैट्रिक फिशर

1
इसे सीधे बंद करना भी संभव होना चाहिए
Ocramius

7
इसका उपयोग केवल दुर्लभ मामलों में किया जाना चाहिए। मैं सुझाव दूंगा कि इसके बजाय कॉलबैक में लिखने के लिए कस्टम तर्क की आवश्यकता नहीं है।
हरमन जे। रडके III

1
मैं आपको पर्याप्त धन्यवाद नहीं दे सकता। इसके अलावा, PHP संस्करण> 5.4 के साथ, आप कॉलबैक के रूप में एक अनाम फ़ंक्शन का उपयोग कर सकते हैं। $this->returnCallback(function() { // ... })
bmorenate

110

नवीनतम phpUnit डॉक्स से: "कभी-कभी तर्कों की पूर्वनिर्धारित तर्कों के आधार पर एक स्टब्ड विधि को अलग-अलग मानों को वापस करना चाहिए। आप एक मैप बनाने के लिए returnValueMap () का उपयोग कर सकते हैं जो संगत रिटर्न मानों के साथ तर्कों को जोड़ता है ।"

$mock->expects($this->any())
    ->method('getConfigValue')
    ->will(
        $this->returnValueMap(
            array(
                array('firstparam', 'secondparam', 'retval'),
                array('modes', 'foo', array('Array', 'of', 'modes'))
            )
        )
    );

3
पोस्ट में लिंक पुराना है, सही एक यहाँ है: returnValueMap ()
hejdav

49

मुझे एक समान समस्या थी (हालांकि थोड़ा अलग ... मुझे तर्कों के आधार पर अलग-अलग रिटर्न वैल्यू की आवश्यकता नहीं थी, लेकिन यह सुनिश्चित करने के लिए परीक्षण करना था कि तर्क के 2 सेट एक ही फ़ंक्शन में पारित किए जा रहे हैं)। मैं इस तरह से कुछ का उपयोग कर ठोकर खाई:

$mock = $this->getMock();
$mock->expects($this->at(0))
    ->method('foo')
    ->with(...)
    ->will($this->returnValue(...));

$mock->expects($this->at(1))
    ->method('foo')
    ->with(...)
    ->will($this->returnValue(...));

यह सही नहीं है, क्योंकि इसके लिए आवश्यक है कि फू () को 2 कॉल का क्रम ज्ञात हो, लेकिन व्यवहार में यह संभवतः बहुत बुरा नहीं है


28

आप शायद एक OOP फैशन में एक कॉलबैक करना चाहते हैं:

<?php
class StubTest extends PHPUnit_Framework_TestCase
{
    public function testReturnAction()
    {
        $object = $this->getMock('class_name', array('method_to_mock'));
        $object->expects($this->any())
            ->method('method_to_mock')
            ->will($this->returnCallback(array($this, 'returnCallback'));

        $object->returnAction('param1');
        // assert what param1 should return here

        $object->returnAction('param2');
        // assert what param2 should return here
    }

    public function returnCallback()
    {
        $args = func_get_args();

        // process $args[0] here and return the data you want to mock
        return 'The parameter was ' . $args[0];
    }
}
?>

16

यह वैसा नहीं है जैसा आप पूछते हैं, बल्कि कुछ मामलों में यह मदद कर सकता है:

$mock->expects( $this->any() ) )
 ->method( 'methodToMock' )
 ->will( $this->onConsecutiveCalls( 'one', 'two' ) );

onConsistentCalls - निर्दिष्ट क्रम में मूल्यों की एक सूची देता है


4

दो स्तर सरणी पास करें, जहां प्रत्येक तत्व एक सरणी है:

  • पहले विधि पैरामीटर हैं, और कम से कम वापसी मूल्य है।

उदाहरण:

->willReturnMap([
    ['firstArg', 'secondArg', 'returnValue']
])

2

आप निम्नानुसार तर्क भी लौटा सकते हैं:

$stub = $this->getMock(
  'SomeClass', array('doSomething')
);

$stub->expects($this->any())
     ->method('doSomething')
     ->will($this->returnArgument(0));

जैसा कि आप Mocking प्रलेखन में देख सकते हैं , विधि returnValue($index)दिए गए तर्क को वापस करने की अनुमति देती है।


0

क्या आपका मतलब कुछ इस तरह का था?

public function TestSomeCondition($condition){
  $mockObj = $this->getMockObject();
  $mockObj->setReturnValue('yourMethod',$condition);
}

मुझे लगता है कि यह SimpleTest कोड है, PHPUnit नहीं। लेकिन नहीं, यह वह नहीं है जो मैं हासिल करना चाहता हूं। कहो कि मेरे पास एक नकली वस्तु थी जो किसी दिए गए नंबर के लिए एक शब्द लौटाती थी। मेरे नकली तरीके को "एक" वापस करने की आवश्यकता होगी जब 1, "दो" के साथ बुलाया जाता है जब 2 आदि के साथ बुलाया जाता है $
बेन डॉवलिंग

0

मेरे पास एक ऐसी ही समस्या थी जो मैं बाहर भी काम नहीं कर सकता था (PHPUnit के बारे में आश्चर्यजनक रूप से बहुत कम जानकारी है)। मेरे मामले में, मैंने बस प्रत्येक परीक्षण को अलग-अलग परीक्षण - ज्ञात इनपुट और ज्ञात आउटपुट बनाया। मुझे एहसास हुआ कि मुझे जैक-ऑफ-ऑल-ट्रेड्स मॉक ऑब्जेक्ट बनाने की ज़रूरत नहीं थी, मुझे केवल एक विशिष्ट परीक्षण के लिए एक विशिष्ट की आवश्यकता थी, और इस प्रकार मैंने परीक्षणों को अलग कर दिया और अपने कोड के अलग-अलग पहलुओं को एक अलग रूप में परीक्षण कर सकता हूं इकाई। मुझे यकीन नहीं है कि यह आपके लिए लागू हो सकता है या नहीं, लेकिन यह वह है जो आपको परीक्षण करने की आवश्यकता है।


दुर्भाग्य से यह मेरी स्थिति में काम नहीं करेगा। मॉक को एक विधि में पारित किया जा रहा है जिसका मैं परीक्षण कर रहा हूं, और परीक्षण विधि अलग-अलग तर्कों के साथ नकली विधि को कॉल करती है। यह जानना दिलचस्प है कि आप समस्या को हल नहीं कर सकते। ऐसा लगता है कि यह एक PHPUnit सीमा हो सकती है।
बेन डॉवलिंग

-1
$this->BusinessMock = $this->createMock('AppBundle\Entity\Business');

    public function testBusiness()
    {
        /*
            onConcecutiveCalls : Whether you want that the Stub returns differents values when it will be called .
        */
        $this->BusinessMock ->method('getEmployees')
                                ->will($this->onConsecutiveCalls(
                                            $this->returnArgument(0),
                                            $this->returnValue('employee')                                      
                                            )
                                      );
        // first call

        $this->assertInstanceOf( //$this->returnArgument(0),
                'argument',
                $this->BusinessMock->getEmployees()
                );
       // second call


        $this->assertEquals('employee',$this->BusinessMock->getEmployees()) 
      //$this->returnValue('employee'),


    }

-2

प्रयत्न :

->with($this->equalTo('one'),$this->equalTo('two))->will($this->returnValue('return value'));

यह उत्तर मूल प्रश्न पर लागू नहीं होता है, लेकिन यह एक समान समस्या का विवरण देता है जो मेरे पास था: सत्यापित करें कि मापदंडों का एक निश्चित सेट प्रदान किया गया है। PHPUnit के साथ () प्रत्येक पैरामीटर के लिए कई तर्कों, एक मिलानकर्ता को स्वीकार करता है।
टाज
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.