2012-09-12 8 views
10

मैं ContainsItalianVatinValidator कस्टम सत्यापनकर्ता का परीक्षण कैसे कर सकता हूं, लेकिन डब्ल्यू * कंटेनर * और validator सेवा (और इस प्रकार, एक स्टब ऑब्जेक्ट बनाएं) तक पहुंचने के बिना?सिम्फनी 2.1 में यूनिट परीक्षण कस्टम सत्यापन बाधा लेकिन कंटेनर तक पहुंच के बिना?

class ContainsItalianVatinValidator extends ConstraintValidator 
{ 
    /** 
    * @param mixed $value 
    * @param \Symfony\Component\Validator\Constraint $constraint 
    */ 
    public function validate($value, Constraint $constraint) 
    {  
     if (!preg_match('/^[0-9]{11}$/', $value, $matches)) { 
      $this->context->addViolation($constraint->message, array(
       '%string%' => $value 
      )); 
     } 

     // Compute and check control code 
     // ... 
    } 
} 

अपने परीक्षण मामले में मुझे लगता है मैं ConstraintViolationList का उपयोग करना चाहिए पता है, लेकिन मैं यह कैसे सत्यापनकर्ता से ही करने के लिए पता नहीं है:

class ContainsItalianVatinValidatorTest extends \PHPUnit_Framework_TestCase 
{ 
    public function testEmptyItalianVatin() 
    { 
     $emptyVatin = ''; 
     $validator = new ContainsItalianVatinValidator(); 
     $constraint = new ContainsItalianVatinConstraint(); 

     // Do the validation 
     $validator->validate($emptyVatin, $constraint); 

     // How can a get a violation list and call ->count()? 
     $violations = /* ... */; 

     // Assert 
     $this->assertGreaterThan(0, $violations->count()); 
    } 
} 
+0

मैं एक सेवा में सत्यापन तर्क निकालेगा और इस सेवा के लिए यूनिट परीक्षण लिखूंगा। सत्यापनकर्ता वर्ग के अंदर आप सेवा के साथ अपनी बाधा जांचते हैं और सत्यापन विफल होने पर एक संदेश जोड़ते हैं। इस प्रकार आपका सत्यापन तर्क ढांचे के साथ नहीं है और भविष्य में बदलावों के लिए अधिक मजबूत है। – fabwu

उत्तर

20

जब आप पर एक नज़र सत्यापनकर्ता के माता-पिता वर्ग Symfony\Component\Validator\ConstraintValidator आप देखते हैं कि initialize नामक एक विधि है जो तर्क के रूप में Symfony\Component\Validator\ExecutionContext का उदाहरण लेती है।

आपके द्वारा सत्यापनकर्ता बनाने के बाद आप initialize विधि को कॉल कर सकते हैं और सत्यापनकर्ता को नकली संदर्भ पास कर सकते हैं। आपको परीक्षण करने की आवश्यकता नहीं है कि addViolation विधि सही तरीके से काम करती है, तो आपको केवल यह जांचना होगा कि इसे कहलाया गया है और यदि इसे सही पैरामीटर के साथ बुलाया जाता है। आप PHPUnit की नकली कार्यक्षमता के साथ ऐसा कर सकते हैं।

... 
$validator = new ContainsItalianVatinValidator(); 
$context = $this->getMockBuilder('Symfony\Component\Validator\ExecutionContext')-> disableOriginalConstructor()->getMock(); 

$context->expects($this->once()) 
    ->method('addViolation') 
    ->with($this->equalTo('[message]'), $this->equalTo(array('%string%', ''))); 

$validator->initialize($context); 

$validator->validate($emptyVatin, $constraint); 
... 
इस कोड को आप संदेश $constraint->message में संग्रहीत के साथ [संदेश] की जगह में

दरअसल, यह सवाल सिम्फनी की तुलना में PHPUnit से अधिक संबंधित है। आप PHPUnit दस्तावेज के दिलचस्प Test Doubles अध्याय पा सकते हैं।

+0

कमाल की अच्छी व्याख्या। एकमात्र चीज जो मुझे नहीं मिल सकती है, आपकी राय में, उल्लंघनों की गिनती गलत है और मुझे बाधा संदेश पर भरोसा क्यों करना चाहिए। वैसे भी, +1। – gremo

+0

आपको उल्लंघनों की गणना क्यों करनी चाहिए। कम से कम आपके प्रश्न में कोड में 'addViolation' के लिए केवल एक कॉल है। यदि उस विधि को एक बार कहा जाता है तो वास्तव में एक उल्लंघन को संदर्भ में जोड़ा जाएगा (सिम्फनी 2 परीक्षण के यूनिट परीक्षण)। –

+0

यदि कोड में 'addViolation'' के लिए और अधिक कॉल होनी चाहिए तो आप कई '$ संदर्भ->' बयानों की अपेक्षा कर सकते हैं जहां प्रत्येक 'addViolation' को एक अलग कॉल को कवर करता है। अफसोस की बात है कि PHPUnit केवल एक विधि 'एक बार' और 'किसी भी' की कॉल की संख्या की गणना करने के लिए दो विधियों की पेशकश करता है। हालांकि, [मॉकरी] (https://github.com/padraic/mockery) एक नकली लाइब्रेरी है जो PHPUnit के साथ संगत है और नकली ऑब्जेक्ट पर विधि कॉल की संख्या को गिन सकता है। –

10

सिम्फनी 2.5+ के लिए अपडेट किया गया। प्रत्येक संभावित संदेश के लिए एक परीक्षण जोड़ें कि आपके सत्यापनकर्ता में validate() विधि उस संदेश को ट्रिगर करने वाले मान के साथ जोड़ सकती है।

<?php 

namespace AcmeBundle\Tests\Validator\Constraints; 

use AcmeBundle\Validator\Constraints\SomeConstraint; 
use AcmeBundle\Validator\Constraints\SomeConstraintValidator; 

/** 
* Exercises SomeConstraintValidator. 
*/ 
class SomeConstraintValidatorTest extends \PHPUnit_Framework_TestCase 
{ 
    /** 
    * Configure a SomeConstraintValidator. 
    * 
    * @param string $expectedMessage The expected message on a validation violation, if any. 
    * 
    * @return AcmeBundle\Validator\Constraints\SomeConstraintValidator 
    */ 
    public function configureValidator($expectedMessage = null) 
    { 
     // mock the violation builder 
     $builder = $this->getMockBuilder('Symfony\Component\Validator\Violation\ConstraintViolationBuilder') 
      ->disableOriginalConstructor() 
      ->setMethods(array('addViolation')) 
      ->getMock() 
     ; 

     // mock the validator context 
     $context = $this->getMockBuilder('Symfony\Component\Validator\Context\ExecutionContext') 
      ->disableOriginalConstructor() 
      ->setMethods(array('buildViolation')) 
      ->getMock() 
     ; 

     if ($expectedMessage) { 
      $builder->expects($this->once()) 
       ->method('addViolation') 
      ; 

      $context->expects($this->once()) 
       ->method('buildViolation') 
       ->with($this->equalTo($expectedMessage)) 
       ->will($this->returnValue($builder)) 
      ; 
     } 
     else { 
      $context->expects($this->never()) 
       ->method('buildViolation') 
      ; 
     } 

     // initialize the validator with the mocked context 
     $validator = new SomeConstraintValidator(); 
     $validator->initialize($context); 

     // return the SomeConstraintValidator 
     return $validator; 
    } 

    /** 
    * Verify a constraint message is triggered when value is invalid. 
    */ 
    public function testValidateOnInvalid() 
    { 
     $constraint = new SomeConstraint(); 
     $validator = $this->configureValidator($constraint->someInvalidMessage); 

     $validator->validate('someInvalidValue', $constraint); 
    } 

    /** 
    * Verify no constraint message is triggered when value is valid. 
    */ 
    public function testValidateOnValid() 
    { 
     $constraint = new SomeConstraint(); 
     $validator = $this->configureValidator(); 

     $validator->validate('someValidValue', $constraint); 
    } 
} 
+0

क्या एक अच्छा जवाब है! आपका बहुत बहुत धन्यवाद! – cezar