2012-11-29 13 views
12

मैं सभी ओवरराइड विधियों के लिए डिफ़ॉल्ट मानों के साथ सेटअप में एक नकली उदाहरण बनाने की कोशिश कर रहा हूं और फिर कई अलग-अलग परीक्षणों में कुछ तरीकों के लिए वापसी मूल्य बदलता हूं जो कि मैं सेट अप किए बिना परीक्षण कर रहा हूं पूरे मॉक क्या इसे करने का कोई तरीका है?क्या मैं इसे सेट करने के बाद PHPUnit Mock पर कोई विधि बदल सकता हूं?

यही मैंने कोशिश की, लेकिन मूर्ख दृष्टिकोण काम नहीं करता है। विधि अभी भी मूल अपेक्षा सेटअप से मूल्य लौटाती है।

पहले स्थापना:

$my_mock->expects($this->any()) 
     ->method('one_of_many_methods') 
     ->will($this->returnValue(true)); 

एक और परीक्षण में एक अलग ज़ोर से पहले:

$my_mock->expects($this->any()) 
     ->method('one_of_many_methods') 
     ->will($this->returnValue(false)); 

इस सवाल का डुप्लिकेट: PHPUnit Mock Change the expectations later, लेकिन है कि एक कोई प्रतिक्रियाएं मिल गया और मैंने सोचा कि एक नया सवाल लाने सकता है सामने मुद्दा।

/** 
* @dataProvider methodValueProvider 
*/ 
public function testMethodReturnValues($method, $expected) { 
    // ... 
    $my_mock->expects($this->any()) 
      ->method($method) 
      ->will($this->returnValue($expected)); 
    // ... 
} 

public function methodValueProvider() { 
    return array(
    array('one_of_many_methods', true), 
    array('another_one_of_many', false) 
); 
} 

संपादित करें::

+0

दुर्भाग्य से phpunit के साथ ऐसी कोई संभावना नहीं है। आप उदाहरण के लिए $ my_mock -> __ phpunit_hasMatchers() का उपयोग कर सकते हैं, लेकिन यह वही नहीं है जो आप चाहते हैं। बेशक आप एक ही विधि पर एक ही विधि पर अलग-अलग रिटर्न वैल्यू सेट कर सकते हैं) "पर" मैचर या बी) "रिटर्न कॉलबैक" लेकिन वे ए) पर निर्भर करते हैं) कॉल पैरामीटर .. लेकिन यह भी नहीं है कि आप क्या खोज रहे हैं। मैं आपको बता दूंगा कि मैं कुछ नया पता लगाता हूं। – Cyprian

+0

यह भी देखें http://stackoverflow.com/questions/5484602/mock-in-phpunit-multiple-configuration-of-the-same-method-with-different-argum/5484864#5484864 – bishop

उत्तर

3

एक तरह से यह करने के लिए की तरह एक data provider, कुछ का उपयोग करने के होगा क्षमा करें, मैं आपके सवाल का पढ़ने में भूलना। उपर्युक्त (स्पष्ट रूप से) वह नहीं है जिसे आप ढूंढ रहे हैं।

1

मैं इस प्रयास नहीं किया है, लेकिन आप परीक्षण में से प्रत्येक में सेटअप में नकली सेट नहीं कर सका ऊपर है, तो:

public function testMethodReturnsTrue 
{ 
    $this->my_mock->will($this->returnValue(true)); 
    $this->assertTrue(...); 
    ... 
} 

मैं नहीं यकीन है कि अगर यह काम करेंगे, जैसा कि मैंने कोशिश कर रहा हूँ कर रहा हूँ परीक्षण में इच्छा() विधि सेट करें, न कि जब प्रारंभिक नकली बनाया गया था।

5

ऐसे मामलों में जहां आप एक ही विधि का एक से अधिक बार उपयोग करते हैं, आपको कोड में निष्पादित उचित गणना के साथ "एट" घोषणा का उपयोग करना चाहिए। इस तरह PHPUnit जानता है कि आपका कौन सा मतलब है, और उम्मीद/दावे को सही ढंग से पूरा कर सकता है। मुझे लगता है कि यह आपके लिए क्या देख रहे है, लेकिन अगर मैं गलत समझ रहा हूँ तो कृपया मुझे बताएं

public function testRunUsingAt() 
    { 
     $test = $this->getMock('Dummy'); 

     $test->expects($this->at(0)) 
      ->method('run') 
      ->with('f', 'o', 'o') 
      ->will($this->returnValue('first')); 

     $test->expects($this->at(1)) 
      ->method('run') 
      ->with('b', 'a', 'r') 
      ->will($this->returnValue('second')); 

     $test->expects($this->at(2)) 
      ->method('run') 
      ->with('l', 'o', 'l') 
      ->will($this->returnValue('third')); 

     $this->assertEquals($test->run('f', 'o', 'o'), 'first'); 
     $this->assertEquals($test->run('b', 'a', 'r'), 'second'); 
     $this->assertEquals($test->run('l', 'o', 'l'), 'third'); 
    } 

:

निम्नलिखित एक सामान्य उदाहरण है, जहां विधि 'रन' कई बार प्रयोग किया जाता है।

अब कुछ भी मजाक करने के मामले में, आप इसे जितनी बार चाहें उतनी बार नकल कर सकते हैं, लेकिन आप इसे सेटअप में उसी नाम से नकल नहीं करना चाहते हैं, अन्यथा जब भी आप इसका इस्तेमाल करते हैं तो आप इसका जिक्र कर रहे हैं सेटअप के लिए। यदि आपको विभिन्न परिदृश्यों में समान विधियों का परीक्षण करने की आवश्यकता है, तो प्रत्येक परीक्षण के लिए इसे नकली करें। आप सेटअप में एक नकली बना सकते हैं, फिर भी एक परीक्षण के लिए एक व्यक्तिगत परीक्षण के भीतर एक समान आइटम के एक अलग मॉक का उपयोग करें, लेकिन वैश्विक नाम की नहीं। use बयान में &

$one_of_many_methods_return = true; 
$my_mock->expects($this->any()) 
     ->method('one_of_many_methods') 
     ->will(
      $this->returnCallback(
       function() use (&$one_of_many_methods_return) { 
        return $one_of_many_methods_return; 
       } 
      )   
     ); 
$this->assertTrue($my_mock->one_of_many_methods()); 

$one_of_many_methods_return = false; 

$this->assertFalse($my_mock->one_of_many_methods());  

नोट:

+5

मुझे लगता है कि यह स्वीकार किया जाना चाहिए उत्तर दें, लेकिन कृपया यह भी ध्यान दें कि आपके द्वारा उपयोग की जाने वाली इंडेक्स उस मॉक ऑब्जेक्ट पर कॉल की कुल संख्या पर आधारित है, उस विशेष विधि को कॉल की संख्या नहीं। इसलिए यदि एक ही वस्तु पर अन्य विधियों के लिए अन्य कॉल किए जाते हैं, तो आपको तदनुसार इंडेक्स में वृद्धि करने की आवश्यकता होगी। – Russ

3

आप इस एक लैम्ब्डा कॉलबैक का उपयोग कर सकता है।

+0

यह एक-ऑफ मानों के लिए उपयोगी है, हालांकि संदर्भों ('$ और $ one_of_many_methods_return') की तुलना में गुणों को साझा करने के लिए परीक्षण विधियों के लिए यह आसान है ('$ this-> one_of_many_methods_return')। आप सीधे विधियों का उपयोग भी कर सकते हैं, जैसे '$ this-> वापसी कॉलबैक ([$ यह,' someMethod ']) '। यह भी ध्यान रखें कि PHP <5.5 अज्ञात कार्यों में '$ this' और निजी/संरक्षित गुण/विधियों का उपयोग करने के बारे में शिकायत कर सकता है। – Warbo

1

नकली विधियों को ओवरराइड करने की कोशिश करने के बजाय, मुझे मॉक किए गए ऑब्जेक्ट्स को ओवरराइड करना आसान लगता है।उदाहरण के लिए:

class ThingTest extends \PHPUnit_Framework_TestCase 
    public function setUp() 
    { 
     $this->initFoo(); 
     $this->initBar(); 
    } 

    public function testOne() 
    { 
     // Uses default [method => value] map for foo and bar 
     $this->assertSomething($this->thing->someMethod()); 
    } 

    public function testTwo() 
    { 
     // Override foo's map 
     $this->initFoo(['method1' => 'some other value']); 
     $this->assertSomethingElse($this->thing->someMethod()); 
    } 

    public function testThree() 
    { 
     // Override bar explicitly, so we can use 'once' 
     $this->initBar([]); 
     $this->bar->expects($this->once()) 
        ->method('method1'); 
     $this->thing->someOtherMethod(); 
    } 

    private function initFoo($methods = null) 
    { 
     $this->init('foo', 
        $this->getMock('Foo'), 
        is_null($methods)? ['method1' => 'default value 1'] 
            : $methods); 
    } 

    private function initBar($methods = null) 
    { 
     $this->init('bar', 
        $this->getMock('Bar'), 
        is_null($methods)? ['method1' => 'default value 1'] 
            : $methods); 
    } 

    private function init($name, $object, $methods) 
    { 
     $this->$name = $object; 
     foreach ($methods as $method => $value) { 
      $this->$name->expects($this->any()) 
         ->method($method) 
         ->will($this->returnValue($value)); 
     } 
     $this->thing = new Thing($this->foo, $this->bar); 
    } 
} 
0

तुम भी एक अलग प्रक्रिया में परीक्षण चला सकते हैं:

/** 
* @runTestsInSeparateProcesses b/c we change the return value of same expectation 
* @see http://stackoverflow.com/questions/13631855 
*/ 
class ThingTest extends \PHPUnit_Framework_TestCase 
{ 
    public function setUp() { 
     $this->config = Mockery::mock('alias:Config'); 
    } 

    public function test_thing_with_valid_config() { 
     $this->config_set('default', 'valid'); 
     $sut = new \Thing(); 
    } 

    /** 
    * @dataProvider provides_broken_configs 
    * @expectedException \RuntimeException 
    */ 
    public function test_thing_with_broken_config($default) { 
     $this->config_set('default', $default); 
     $sut = new \Thing(); 
    } 

    public function provides_broken_configs() { 
     return [ [ null ] ]; 
    } 

    protected function config_set($key, $value) { 
     $this->config->shouldReceive('get')->with($key)->andReturn($value); 
    } 
} 

इस उदाहरण में, मैं मजाक का उपयोग करने की हो, लेकिन पैटर्न में ही है। चूंकि प्रत्येक टेस्ट में प्रत्येक मेमोरी के माध्यम से ताजा मेमोरी होती है, इसलिए हमें पहले सेट अपेक्षाओं को "ओवरराइडिंग" की सीमा का सामना नहीं करना पड़ता है।