2013-09-01 6 views
25

क्या अक्षम कन्स्ट्रक्टर के साथ एक मॉक ऑब्जेक्ट बनाना और मैन्युअल रूप से संरक्षित गुण सेट करना संभव है?phpunit - mockbuilder - सेट मॉक ऑब्जेक्ट आंतरिक प्रॉपर्टी

यहाँ एक मूर्खतापूर्ण उदाहरण है:

class A { 
    protected $p; 
    public function __construct(){ 
     $this->p = 1; 
    } 

    public function blah(){ 
     if ($this->p == 2) 
      throw Exception(); 
    } 
} 

class ATest extend bla_TestCase { 
    /** 
     @expectedException Exception 
    */ 
    public function testBlahShouldThrowExceptionBy2PValue(){ 
     $mockA = $this->getMockBuilder('A') 
      ->disableOriginalConstructor() 
      ->getMock(); 
     $mockA->p=2; //this won't work because p is protected, how to inject the p value? 
     $mockA->blah(); 
    } 
} 

तो मैं पी मूल्य जो सुरक्षित है इंजेक्षन करना चाहते हैं, तो मैं नहीं कर सकता। क्या मुझे सेटर या आईओसी परिभाषित करना चाहिए, या मैं इसे phpunit के साथ कर सकता हूं?

+1

सिर्फ रिकॉर्ड के लिए - यदि आप गैर-सार्वजनिक एपीआई का परीक्षण कर रहे हैं, तो आप इसे गलत कर रहे हैं। यूनिट परीक्षण परीक्षण के व्यवहार के बारे में है, आंतरिक कार्यान्वयन नहीं। –

उत्तर

35

आप प्रतिबिंब का उपयोग करके संपत्ति सार्वजनिक कर सकते हैं, और फिर इच्छित मान सेट:

$a = new A; 
$reflection = new ReflectionClass($a); 
$reflection_property = $reflection->getProperty('p'); 
$reflection_property->setAccessible(true); 

$reflection_property->setValue($a, 2); 

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

तो, बजाय पी = 2 तो एक अपवाद उठाया है की स्थापना की है, तो आप नकली कॉन्फ़िगर एक अपवाद जब blah विधि कहा जाता है को बढ़ाने के लिए:

$mockA = $this->getMockBuilder('A') 
     ->disableOriginalConstructor() 
     ->getMock(); 
$mockA->expects($this->any()) 
     ->method('blah') 
     ->will($this->throwException(new Exception)); 

अंतिम, यह अजीब है कि आप मजाक कर रहे हैं एटीस्ट में एक कक्षा। आप आम तौर पर उस ऑब्जेक्ट द्वारा आवश्यक निर्भरताओं का नकल करते हैं जो आप परीक्षण कर रहे हैं।

उम्मीद है कि इससे मदद मिलती है।

/** 
* Sets a protected property on a given object via reflection 
* 
* @param $object - instance in which protected value is being modified 
* @param $property - property on instance being modified 
* @param $value - new value of the property being modified 
* 
* @return void 
*/ 
public function setProtectedProperty($object, $property, $value) 
{ 
    $reflection = new ReflectionClass($object); 
    $reflection_property = $reflection->getProperty($property); 
    $reflection_property->setAccessible(true); 
    $reflection_property->setValue($object, $value); 
} 
+1

कक्षा ए पूरी तरह से इंजेक्शन नहीं है, मैं इसके रचनाकार में कई कक्षाओं का नया उदाहरण बना रहा हूं ... इसलिए मुझे उन उदाहरणों को मजाक करने के लिए निर्माता को ओवरराइड करने की आवश्यकता है। सबसे अच्छा तरीका नहीं, मुझे लगता है कि मैं इसके बजाय निर्भरता इंजेक्शन कंटेनर का उपयोग करूंगा। – inf3rno

+0

आपका कोड निश्चित रूप से अधिक परीक्षण योग्य होगा। DI को लागू करने के लिए कई विकल्प हैं, लेकिन यह वास्तव में एक सरल है: http://pimple.sensiolabs.org/ – gontrollez

+2

परीक्षण में निर्भरता इंजेक्शन कंटेनर का उपयोग न करें! एक अच्छा यूनिट परीक्षण केवल एक वर्ग का परीक्षण करता है, और सभी निर्भरताओं को पूरी तरह कॉन्फ़िगर किए गए मैक्स के रूप में इंजेक्शन दिया जाता है। यदि आप ऐसा नहीं कर सकते हैं, तो आपके पास एक खराब वास्तुकला है जिसे सुधारना चाहिए। '$ A-> p = 2;' के बजाय – Sven

10

सोचा था कि मैं एक आसान सहायक विधि है कि जल्दी से कॉपी किया जा सकता है और यहाँ चिपकाया छोड़ होता

public function __construct(BlahClass $blah) 
{ 
    $this->protectedProperty = new FooClass($blah); 
} 

आप कन्स्ट्रक्टर में एक नकली BlahClass का उपयोग कर सकते हैं, लेकिन फिर कन्स्ट्रक्टर किसी संरक्षित संपत्ति को उस चीज़ पर सेट करता है जिसे आप नकली नहीं कर सकते।

तो शायद आप सोच रहे हैं "ब्लाह क्लास के बजाय फूक्लास लेने के लिए कन्स्ट्रक्टर को अच्छी तरह से रिएक्टर करें, तो आपको कन्स्ट्रक्टर में FooClass को तुरंत चालू करने की आवश्यकता नहीं है, और आप इसके बजाय एक नकली डाल सकते हैं!" खैर, आप सही होंगे, अगर इसका मतलब यह नहीं था कि आपको क्लाउड के प्रत्येक उपयोग को पूरे कोडबेस में बदलना होगा ताकि उसे BlahClass के बजाय FooClass दिया जा सके।

प्रत्येक कोडबेस सही नहीं है, और कभी-कभी आपको केवल सामान प्राप्त करने की आवश्यकता होती है। और इसका मतलब है, हां, कभी-कभी आपको "केवल परीक्षण सार्वजनिक एपीआई" नियम तोड़ने की आवश्यकता होती है।

-1

यह आश्चर्यजनक होगा हर codebase डि और आईओसी इस्तेमाल किया, और इस तरह सामान कभी नहीं किया है, तो:

+1

-> अक्षम ऑरिगिनल कन्स्ट्रक्टर? –

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