2012-10-13 4 views
8

कार्य करने के लिए वें फोन पर फेंक दिया जाता है आप एक तरीका है जिसके अंत मेंयूनिट परीक्षण है कि अपवाद

class Pager 
{ 
    private $i; 

    public function next() 
    { 
     if ($this->i >= 3) { 
      throw new OutOfBoundsException(); 
     } 

     $this->i++; 
    } 
} 

करने पर निर्भर करता है कहो कैसे आप इकाई इस वर्ग के परीक्षण होगा। अर्थात। परीक्षण करें कि PHPUnit का उपयोग कर next() की तीसरी कॉल पर अपवाद फेंक दिया गया है या नहीं? मैंने अपना प्रयास एक उत्तर के रूप में जोड़ा है, लेकिन मुझे यकीन नहीं है कि यह वास्तव में जाने का तरीका है या नहीं।

+2

@PeeHaa - ऐसा लगता है कि आप 'phpunit' टैग को याद करते हैं। मुझे लगता है कि सवाल यह है कि कैसे * इकाई परीक्षण * है कि अपवाद तीसरे कॉल पर होता है। – Spudley

उत्तर

7

पहले दो कॉल पर null के लिए परीक्षण और यह भी अपवाद के लिए परीक्षण के बारे में क्या की तरह फेंके जाने इस प्रकार है:

class PagerTest 
{ 
    public function setUp() 
    { 
     $this->pager = new Pager(); 
    } 

    public function testTooManyNextCalls() 
    { 
     $this->assertNull($this->pager->next()); 
     $this->assertNull($this->pager->next()); 
     $this->assertNull($this->pager->next()); 

     $this->setExpectedException('OutOfBoundsException'); 
     $this->pager->next(); 
    } 
} 
+0

यह मेरे पास जितना था उससे ज्यादा क्लीनर है, और जैसा कि मैं चाहता था, इस तरह के दावे का उपयोग करता है। विश्वास नहीं कर सकता मैंने इस विधि के बारे में नहीं सोचा था! – Shane

+1

आपको वास्तव में परीक्षण करना चाहिए कि यह इरादा के रूप में काम करता है या नहीं। क्योंकि मैं अपने सिर के शीर्ष पर 100% निश्चित नहीं हूं कि यह पहले या दूसरे 'अगले()' कॉल पर अपवाद फेंकने पर गुजरता या विफल हो जाता है। – PeeHaa

+0

@PeeHaa - आपकी टिप्पणी फिर से करें: क्या पहले सेट के बाद 'setExpectedException' कॉल को स्थानांतरित किया जा सकता है, ताकि यह तीसरी कॉल तक अपवाद की अपेक्षा न करे? – Spudley

1

इस समय मेरे पास क्या है, लेकिन मैं सोच रहा था कि ऐसा करने के कोई बेहतर तरीके हैं या नहीं।

class PagerTest 
{ 
    public function setUp() 
    { 
     $this->pager = new Pager(); 
    } 

    public function testTooManyNextCalls() 
    { 
     for ($i = 0; $i < 10; $i++) { 
      try { 
       $this->pager->next(); 
      } catch(OutOfBoundsException $e) { 
       if ($i == 3) { 
        return; 
       } else { 
        $this->fail('OutOfBoundsException was thrown unexpectedly, on iteration ' . $i); 
       } 
      } 

      if ($i > 3) { 
       $this->fail('OutOfBoundsException was not thrown when expected'); 
      } 
     } 
    } 
} 
+0

जब तक कोई दृष्टिकोण आपकी समस्या का समाधान न हो, तो कृपया इसे अपने प्रश्न में रखें। –

+1

यह एक समाधान है, हालांकि मैं बेहतर एक के लिए उम्मीद कर रहा था। – Shane

0

आप इस मूल्य को $- पास कर सकते हैं-> मैं अपवाद तत्कालता के लिए, जो अपवाद का संदेश होगा।

class Pager 
{ 
    private $i; 

    public function next() 
    { 
     if ($this->i >= 3) { 
      throw new OutOfBoundsException($this->i); 
     } 

     $this->i++; 
    } 
} 
$a=new Pager(); 
$a->next(); 
$a->next(); 
$a->next(); 
$a->next(); 

//outputs: "Exception: 3" 
+0

मैं एक PHPUnit समाधान की उम्मीद कर रहा था। हालांकि धन्यवाद! – Shane

0

आप की तरह कुछ इस्तेमाल कर सकते हैं: एक अपवाद 3 विधि कॉल में फेंक दिया जाता है, तो

class PagerTest extends PHPUnit_Framework_TestCase { 

    /** 
    * @expectedException OutOfBoundsException 
    */ 
    public function testTooManyNextCalls() { 
     $this->pager = new Pager(); 

     $this->pager->next(); 
     $this->pager->next(); 
     $this->pager->next(); 

     $this->assertTrue(false); 
    } 
} 

, सदा असफल रहने पर जोर बयान कभी नहीं पहुँच जाना चाहिए और टेस्ट पास करना चाहिए। दूसरी ओर यदि कोई अपवाद नहीं फेंक दिया जाता है, तो परीक्षण विफल हो जाएगा।

+1

निश्चित नहीं है लेकिन अपवाद तब भी होगा जब अपवाद पहली/दूसरी कॉल पर फेंक दिया जाता है? – PeeHaa

+0

आप सही हैं - किसी भी कॉल से अपवाद उस परीक्षा पास करेगा। एक दूसरी टेस्ट कॉलिंग केवल 2 बार इस के आसपास काम कर सकती है लेकिन फिर भी यह एक इष्टतम समाधान नहीं है। – user1708452

4

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

तो ओपी के कोड के लिए इसका क्या अर्थ है? आइए सार्वजनिक Pager::next विधि देखें। कोड जो Pager वर्ग एपीआई परवाह नहीं करताPager::next निर्धारित करता है कि कोई अपवाद फेंक दिया जाना चाहिए या नहीं। यह केवल परवाह करता है कि Pager::next वास्तव में कुछ गलत होने पर अपवाद फेंकता है।

हम यह जांचना नहीं चाहते कि OutOfBoundsException फेंकने के फैसले पर विधि कैसे आती है - यह एक कार्यान्वयन विस्तार है। हम केवल यह जांचना चाहते हैं कि उचित होने पर ऐसा होता है।

तो इस परिदृश्य का परीक्षण करने के लिए हम एक ऐसी स्थिति का अनुकरण करते हैं जिसमें Pager::next फेंक देगा। इसे पूरा करने के लिए हम बस "परीक्षण सीम" कहलाते हैं। ...

<?php 
class Pager 
{ 
    protected $i; 

    public function next() 
    { 
     if ($this->isValid()) { 
      $this->i++; 
     } else { 
      throw new OutOfBoundsException(); 
     } 
    } 

    protected function isValid() { 
     return $this->i < 3; 
    } 
} 

उपरोक्त कोड में, संरक्षित Pager::isValid विधि हमारे परीक्षण सीवन है। यह हमारे कोड (इसलिए नाम) में एक सीम का खुलासा करता है जिसे हम परीक्षण उद्देश्यों के लिए देख सकते हैं।परीक्षण है कि Pager::next$i का अमान्य मान के लिए एक अपवाद फेंकता है, हमारे नए परीक्षण सीवन और PHPUnit के मजाक API का उपयोग करना मामूली बात है:

class PagerTest extends PHPUnit_Framework_TestCase 
{ 
    /** 
    * @covers Pager::next 
    * @expectedException OutOfBoundsException 
    */ 
    public function testNextThrowsExceptionOnInvalidIncrementValue() { 
     $pagerMock = $this->getMock('Pager', array('isValid')); 
     $pagerMock->expects($this->once()) 
        ->method('isValid') 
        ->will($this->returnValue(false)); 
     $pagerMock->next(); 
    } 
} 

सूचना कैसे इस परीक्षण विशेष रूप से परवाह नहीं करता कैसे कार्यान्वयन विधि Pager::isValid निर्धारित करता है कि वर्तमान वृद्धि अवैध है। यह परीक्षण केवल false को वापस आने के लिए विधि को झुकाता है ताकि हम यह जांच सकें कि हमारे सार्वजनिक Pager::next विधि ऐसा करने पर अपवाद फेंकता है।

PHPUnit mocking API पूरी तरह से Test Doubles section of the PHPUnit manual में शामिल है। एपीआई दुनिया के इतिहास में सबसे सहज ज्ञान नहीं है, लेकिन कुछ बार-बार उपयोग के साथ यह आम तौर पर समझ में आता है।

+1

उत्तर संपादित किए बिना मैं encapsulation मुद्दों पर ध्यान आकर्षित करना चाहता हूं। आम तौर पर आप 'निजी' चीजें 'निजी' रखना चाहते हैं, लेकिन ध्यान दें कि आप 'निजी' उदाहरण विधियों का नकल नहीं कर सकते हैं। ऐसे मामलों में जहां कार्यान्वयन विधि या संपत्ति की पहुंच कम हो सकती है, टेस्टेबिलिटी में सुधार कर सकती है (उदाहरण के लिए मॉकिंग की अनुमति देने के लिए), यह मेरी मजबूत राय है कि 'संरक्षित' सहायक है और encapsulation चिंताओं को नजरअंदाज किया जा सकता है। – rdlowrey

+0

किसी बिंदु पर आपको 'isValid' और 'पेजर :: अगला' के लिए समग्र अनुबंध का परीक्षण करना होगा, जो क्लाइंट कोड * परवाह करता है। यदि वैधता परीक्षण 'पेजर' के बाहर बाहरी था, तो मैं इस विधि का उपयोग करता हूं लेकिन यहां नहीं। –

+0

@ डेविड हार्केनेस परीक्षण 'isValid' समझा जाना चाहिए; यह किया जाना चाहिए। मुद्दा यह है कि आपको इसे सीधे परीक्षण नहीं करना चाहिए, आपको ऐसे परिदृश्य में सार्वजनिक इंटरफ़ेस का परीक्षण करके 'isValid' पर परीक्षण कवरेज प्राप्त करना चाहिए जहां आप इसके परिणामों का मज़ाक उड़ा रहे हैं। हमें 'i i = = 3' का मूल्यांकन करने की PHP की क्षमता का सीधे परीक्षण करने की आवश्यकता नहीं है। इसे 'पेजर' को विस्तारित कस्टम स्टब क्लास के साथ आसानी से हासिल किया जा सकता है, लेकिन उदाहरण PHP क्षमताओं का प्रदर्शन करने के लिए PHPUnit के मॉकिंग एपीआई का उपयोग करता है। जाहिर है, यह एक बहुत ही सरल परिदृश्य है ... जिसमें एक पूर्ण परीक्षण परीक्षाएं ओवरकिल की तरह महसूस करती हैं। अवधारणा यह महत्वपूर्ण है। – rdlowrey