2012-06-29 11 views
5

मैं Phactory, और PHPUnit का उपयोग कर PHP Propel प्रोजेक्ट के लिए एक परीक्षण सूट सेट करने पर काम कर रहा हूं। मैं वर्तमान में फ़ंक्शन का परीक्षण करने की कोशिश कर रहा हूं जो बाहरी अनुरोध करता है, और मैं उस अनुरोध के लिए एक नकली प्रतिक्रिया में स्टब करना चाहता हूं।मैं PHPUnit में बाहरी वेब अनुरोध का नकल कैसे कर सकता हूं?

यहाँ वर्ग मैं परीक्षण करने के लिए कोशिश कर रहा हूँ का एक टुकड़ा है:

class Endpoint { 
    ... 
    public function parseThirdPartyResponse() { 
    $response = $this->fetchUrl("www.example.com/api.xml"); 
    // do stuff and return 
    ... 
    } 

    public function fetchUrl($url) { 
    return file_get_contents($url); 
    } 
    ... 

और यहाँ परीक्षण समारोह मैं लिखने के लिए कोशिश कर रहा हूँ है।

// my factory, defined in a seperate file 
Phactory::define('endpoint', array('identifier' => 'endpoint_$n'); 

// a test case in my endpoint_test file 
public function testParseThirdPartyResponse() { 
    $phEndpoint = Phactory::create('endpoint', $options); 
    $endpoint = new EndpointQuery()::create()->findPK($phEndpoint->id); 

    $stub = $this->getMock('Endpoint'); 
    $xml = "...<target>test_target</target>..."; // sample response from third party api 

    $stub->expects($this->any()) 
     ->method('fetchUrl') 
     ->will($this->returnValue($xml)); 

    $result = $endpoint->parseThirdPartyResponse(); 
    $this->assertEquals('test_target', $result); 
} 

मैं अब देख सकते हैं, मैं अपने परीक्षण कोड की कोशिश की के बाद, कि मैं getMock साथ एक नकली वस्तु बनाने रहा हूँ, और फिर कभी नहीं इसे का उपयोग। तो फ़ंक्शन fetchUrl वास्तव में निष्पादित करता है, जो मैं नहीं चाहता हूं। लेकिन मैं अभी भी का उपयोग करने में सक्षम होना चाहता हूं, फैक्टरी ने endpoint ऑब्जेक्ट बनाया है, क्योंकि इसमें सभी सही फ़ील्ड मेरी फैक्टरी परिभाषा से आबादी है।

क्या मेरे पास किसी मौजूदा ऑब्जेक्ट पर विधि को रोकने का कोई तरीका है? तो मैं fetch_url$endpoint एंडपॉइंट ऑब्जेक्ट पर अभी बनाया था?

या मैं इस सब गलत के बारे में जा रहा हूं; मेरे पास बाहरी वेब अनुरोधों पर भरोसा करने वाले मेरे फ़ंक्शन यूनिट परीक्षण के लिए एक बेहतर तरीका है?

मैंने "स्टब्बिंग और मॉकिंग वेब सर्विसेज" के संबंध में PHPUnit दस्तावेज पढ़ा है, लेकिन ऐसा करने के लिए उनका नमूना कोड 40 लाइन लंबा है, जिसमें आपके स्वयं के wsdl को परिभाषित करने सहित शामिल नहीं है। मुझे विश्वास है कि यह मेरे लिए इसे संभालने का सबसे सुविधाजनक तरीका है, जब तक कि एसओ के अच्छे लोग दृढ़ता से अन्यथा महसूस न करें।

किसी भी मदद की बहुत सराहना करते हैं, मुझे इस दिन लटका दिया गया है। धन्यवाद!!

उत्तर

11

एक परीक्षण दृष्टिकोण से, अपने कोड दो समस्याएं हैं:

  1. यूआरएल, हार्डकोडेड है आप विकास, परीक्षण या उत्पादन के लिए यह फेरबदल का कोई रास्ता नहीं छोड़ने
  2. Endpoint डेटा पुनः प्राप्त करने के तरीके के बारे में जानता है । आपके कोड से मैं यह नहीं कह सकता कि एंडपॉइंट वास्तव में क्या करता है, लेकिन यदि यह निम्न स्तर नहीं है "बस मुझे डेटा प्राप्त करें" ऑब्जेक्ट, यह डेटा को पुनर्प्राप्त करने के तरीके के बारे में नहीं पता होना चाहिए।

इस तरह के आपके कोड के साथ, आपके कोड का परीक्षण करने के लिए कोई अच्छा तरीका नहीं है। आप प्रतिबिंब के साथ काम कर सकते हैं, अपना कोड बदल सकते हैं और इसी तरह। इस दृष्टिकोण के साथ समस्या यह है कि आप अपने वास्तविक वस्तु का परीक्षण नहीं करते हैं, लेकिन कुछ प्रतिबिंब जो परीक्षण के साथ काम करने के लिए बदल जाते हैं।

आप लिखना चाहते हैं, तो "अच्छा" परीक्षण, अपने endpoint कुछ इस तरह दिखना चाहिए:

class Endpoint { 

    private $dataParser; 
    private $endpointUrl; 

    public function __construct($dataParser, $endpointUrl) { 
     $this->dataPartser = $dataParser; 
     $this->endpointUrl = $endpointUrl; 
    } 

    public function parseThirdPartyResponse() { 
     $response = $this->dataPartser->fetchUrl($this->endpointUrl); 
     // ... 
    } 
} 

अब आप जो क्या आप परीक्षण करना चाहते हैं पर निर्भर करता कुछ डिफ़ॉल्ट प्रतिक्रिया लौटाता DataParser का एक नकली इंजेक्षन सकता है ।

अगला प्रश्न यह हो सकता है: मैं डेटापार्सर का परीक्षण कैसे करूं? ज्यादातर, आप नहीं करते हैं। यदि यह PHP मानक कार्यों के आसपास सिर्फ एक रैपर है, तो आपको इसकी आवश्यकता नहीं है।आपका DataParser वास्तव में, बहुत कम स्तर होना चाहिए इस तरह की तलाश में:

class DataParser { 
    public function fetchUrl($url) { 
     return file_get_contents($url); 
    } 
} 

आप की जरूरत है या यह परीक्षण करना चाहते हैं, तो आप के रूप में एक "नकली" एक वेब सेवा है जो आपके परीक्षण और कृत्यों के अंदर रहता है बना सकते हैं, हमेशा पहले से कॉन्फ़िगर लौटने डेटा। फिर आप वास्तविक के बजाय इस नकली यूआरएल को कॉल कर सकते हैं और वापसी का मूल्यांकन कर सकते हैं।

+2

यही वह है जो मैंने किया, हालांकि मैं इसके साथ रोमांचित नहीं हूं। मेरे लिए ओवरकिल की तरह 'file_get_contents' _feels_ को लपेटने के लिए बस एक अतिरिक्त कक्षा। यह एक कोड परिवर्तन है, मैं केवल इसका परीक्षण करने के लिए बना रहा हूं, और यह मुझे लगता है। मैं रूबी से आ रहा हूं, जिसमें [वेबमॉक] (https://github.com/bblimke/webmock/) मणि था, जो आपने अपने पिछले पैराग्राफ में वर्णित किया है: "एक वेबसाइट सेवा बनाता है जो आपके परीक्षणों में रहता है और एक "मॉक" के रूप में कार्य करता है, हमेशा पूर्वसंरचित डेटा लौटाता है "। कोडिंग के बदले में मैं खुद के लिए नकली वस्तु मार्ग जाउंगा। विचारों के लिए धन्यवाद! – goggin13

+2

मुझे नहीं लगता कि यह ओवरहेड है। इस तरह के बारे में सोचें: आप इस कोड का उपयोग कई स्थानों पर करने जा रहे हैं। अब से एक वर्ष, file_get_contents के लिए बेहतर कार्यान्वयन का एक तरीका है और आपको इसे हर जगह बदलना होगा। या लगता है कि आप बज़ पर स्विच करना चाहते हैं (जिसे मैं अनुशंसा करता हूं)। उपर्युक्त कोड में, आप ऑब्जेक्ट इंजेक्ट करते हैं और एक विधि कॉल को बदलना होगा। Mayvbe यह आपके छोटे उदाहरण में ओवरहेड है, लेकिन जैसे ही आपका एप्लिकेशन बड़ा हो जाता है और आप file_get_contents का पुन: उपयोग करना चाह सकते हैं, आप इसकी सराहना कर सकते हैं। – Sgoettschkes

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