2011-11-07 16 views
15

का उपयोग करके अमूर्त वर्ग में कंक्रीट विधि का मजाक कर रहे हैं क्या PHPUnit का उपयोग करके अमूर्त कक्षाओं में ठोस तरीकों का नकल करने के कोई अच्छे तरीके हैं?phpunit

मैं अब तक है क्या पाया है:

  • उम्मीद() ->() ठीक सार तरीकों
  • यह ठोस तरीकों के लिए काम नहीं करता है का उपयोग कर काम करता है जाएगा। मूल विधि इसके बजाए चलाया जाता है।
  • मॉकबिल्डर का उपयोग करना और सभी अमूर्त विधियों और सेट विधिओं() कार्यों को कंक्रीट विधि देना। हालांकि, यह आपको सभी अमूर्त तरीकों को निर्दिष्ट करने की आवश्यकता है, परीक्षण को नाजुक और बहुत वर्बोज़ बनाना।
  • मॉकबिल्डर :: getMockForAbstractClass() setMethod() को अनदेखा करता है।


यहाँ ऊपर अंक examplifying कुछ इकाई परीक्षण कर रहे हैं:

abstract class AbstractClass { 
    public function concreteMethod() { 
     return $this->abstractMethod(); 
    } 

    public abstract function abstractMethod(); 
} 


class AbstractClassTest extends PHPUnit_Framework_TestCase { 
    /** 
    * This works for abstract methods. 
    */ 
    public function testAbstractMethod() { 
     $stub = $this->getMockForAbstractClass('AbstractClass'); 
     $stub->expects($this->any()) 
       ->method('abstractMethod') 
       ->will($this->returnValue(2)); 

     $this->assertSame(2, $stub->concreteMethod()); // Succeeds 
    } 

    /** 
    * Ideally, I would like this to work for concrete methods too. 
    */ 
    public function testConcreteMethod() { 
     $stub = $this->getMockForAbstractClass('AbstractClass'); 
     $stub->expects($this->any()) 
       ->method('concreteMethod') 
       ->will($this->returnValue(2)); 

     $this->assertSame(2, $stub->concreteMethod()); // Fails, concreteMethod returns NULL 
    } 

    /** 
    * One way to mock the concrete method, is to use the mock builder, 
    * and set the methods to mock. 
    * 
    * The downside of doing it this way, is that all abstract methods 
    * must be specified in the setMethods() call. If you add a new abstract 
    * method, all your existing unit tests will fail. 
    */ 
    public function testConcreteMethod__mockBuilder_getMock() { 
     $stub = $this->getMockBuilder('AbstractClass') 
       ->setMethods(array('concreteMethod', 'abstractMethod')) 
       ->getMock(); 
     $stub->expects($this->any()) 
       ->method('concreteMethod') 
       ->will($this->returnValue(2)); 

     $this->assertSame(2, $stub->concreteMethod()); // Succeeds 
    } 

    /** 
    * Similar to above, but using getMockForAbstractClass(). 
    * Apparently, setMethods() is ignored by getMockForAbstractClass() 
    */ 
    public function testConcreteMethod__mockBuilder_getMockForAbstractClass() { 
     $stub = $this->getMockBuilder('AbstractClass') 
       ->setMethods(array('concreteMethod')) 
       ->getMockForAbstractClass(); 
     $stub->expects($this->any()) 
       ->method('concreteMethod') 
       ->will($this->returnValue(2)); 

     $this->assertSame(2, $stub->concreteMethod()); // Fails, concreteMethod returns NULL 
    } 
} 
+0

आप सार वर्गों का परीक्षण करने के रूप में वे सार हैं की जरूरत नहीं है:

कोड देखें। या आप एक सार टेस्टकेस भी लिखना चाहते हैं? – hakre

+0

अमूर्त वर्ग एक और वर्ग की निर्भरता है। इसलिए मैं कुछ क्लास :: getMyCalculatedValue() का परीक्षण करना चाहता हूं जो $ object-> concreteMethod() का उपयोग करता है। चूंकि concreteMethod() बदल सकता है या स्थापित करना मुश्किल हो सकता है, इसलिए मैं concreteMethod() के वापसी मान निर्दिष्ट करना चाहता हूं। – CheeseSucker

उत्तर

4

मैं सभी सार तरीकों में जोड़ने के लिए है क्योंकि आप चाहिए उन सब को वैसे भी नकली मेरी आधार परीक्षण मामले में getMock() ओवरराइड। आप बिल्डर के साथ कुछ ऐसा ही कर सकते हैं।

महत्वपूर्ण: आप निजी तरीकों का नकल नहीं कर सकते हैं।

public function getMock($originalClassName, $methods = array(), array $arguments = array(), $mockClassName = '', $callOriginalConstructor = TRUE, $callOriginalClone = TRUE, $callAutoload = TRUE) { 
    if ($methods !== null) { 
     $methods = array_unique(array_merge($methods, 
       self::getAbstractMethods($originalClassName, $callAutoload))); 
    } 
    return parent::getMock($originalClassName, $methods, $arguments, $mockClassName, $callOriginalConstructor, $callOriginalClone, $callAutoload); 
} 

/** 
* Returns an array containing the names of the abstract methods in <code>$class</code>. 
* 
* @param string $class name of the class 
* @return array zero or more abstract methods names 
*/ 
public static function getAbstractMethods($class, $autoload=true) { 
    $methods = array(); 
    if (class_exists($class, $autoload) || interface_exists($class, $autoload)) { 
     $reflector = new ReflectionClass($class); 
     foreach ($reflector->getMethods() as $method) { 
      if ($method->isAbstract()) { 
       $methods[] = $method->getName(); 
      } 
     } 
    } 
    return $methods; 
} 
+0

यह काम करता है। मुझे निजी तरीकों का नकल करने की आवश्यकता नहीं है =) – CheeseSucker

+0

यह 'getMockForAbstractClass' से अलग कैसे है? – FoolishSeth

+1

@FoolishSeth PHPUnit के पिछले संस्करणों ने आपको [नकली करने के लिए अतिरिक्त ठोस तरीकों को निर्दिष्ट करने की अनुमति नहीं दी] (https://github.com/sebastianbergmann/phpunit-mock-objects/pull/49)। चूंकि आप प्रत्येक अमूर्त विधि को मजाक किए बिना नकली वस्तु को तुरंत चालू नहीं कर सकते हैं, इसलिए 'getMock() 'et al को कॉल करते समय उन्हें सूची में विलय करना उचित लगता है। –

14

2 साल पहले इस के लिए एक पुल का अनुरोध था, लेकिन जानकारी दस्तावेज में शामिल कर लिया गया कभी नहीं: https://github.com/sebastianbergmann/phpunit-mock-objects/pull/49

आप getMockForAbstractClass का तर्क 7 में एक सरणी में अपने ठोस विधि पारित कर सकते हैं()। https://github.com/andreaswolf/phpunit-mock-objects/blob/30ee7452caaa09c46421379861b4128ef7d95e2f/PHPUnit/Framework/MockObject/Generator.php#L225

 संबंधित मुद्दे