2014-06-06 14 views
14

Ho una domanda per il test di Symfony FormType. http://symfony.com/doc/current/cookbook/form/unit_testing.htmlSymfony FormType contratto di prova con EntityType

Nei miei tipi di modulo il tipo entity è comune. Testare i tipi di modulo con un tipo di modulo entità dottrina è orribile.

Questo è il mio campo modulo.

public function buildForm(FormBuilderInterface $builder, array $options) 
{ 
    $builder->add('products', 'entity', array(
     'class'  => 'AcmeDemoBundle:Product', 
     'label'  => 'Product', 
     'property' => 'name', 
     'required' => false, 
     'mapped' => true, 
     'multiple' => true, 
     'expanded' => true 
    )); 
} 

Ed ecco il mock per il campo.

private function getEntityTypeMock() 
{ 
    $entityRepositoryMock = $this->getMockBuilder('Doctrine\ORM\EntityRepository') 
     ->disableOriginalConstructor() 
     ->getMock() 
    ; 

    $entityRepositoryMock->expects($this->once()) 
     ->method('findAll') 
     ->will($this->returnValue(array())); 

    $classMetaDataMock = $this->getMockBuilder('Doctrine\ORM\Mapping\ClassMetadata') 
     ->disableOriginalConstructor() 
     ->getMock(); 

    $mockEntityManager = $this->getMockBuilder('Doctrine\ORM\EntityManager') 
     ->disableOriginalConstructor() 
     ->getMock(); 

    $mockEntityManager->expects($this->any()) 
     ->method('getClassMetadata') 
     ->will($this->returnValue($classMetaDataMock)); 

    $mockEntityManager->expects($this->once()) 
     ->method('getRepository') 
     ->will($this->returnValue($entityRepositoryMock)); 

    $mockRegistry = $this->getMockBuilder('Doctrine\Bundle\DoctrineBundle\Registry') 
     ->disableOriginalConstructor() 
     ->getMock(); 

    $mockRegistry->expects($this->any()) 
     ->method('getManagerForClass') 
     ->will($this->returnValue($mockEntityManager)); 

    $mockEntityType = $this->getMockBuilder('Symfony\Bridge\Doctrine\Form\Type\EntityType') 
     ->setMethods(array('getName')) 
     ->setConstructorArgs(array($mockRegistry)) 
     ->getMock(); 

    $mockEntityType->expects($this->any())->method('getName') 
     ->will($this->returnValue('entity')); 

    return $mockEntityType; 
} 

È davvero il modo corretto? Dentro lo TypeTestCase non ho accesso a niente, nessun contenitore nessun kernel, niente. Questo rende il test di un tipo di modulo piuttosto difficile e frustrante.

C'è un modo migliore per testare i tipi di modulo? O un modo più semplice per gestire i tipi che hanno una dipendenza ORM?

Cheers.

+2

Attualmente, Symfony supporta EntityType fuori dalla scatola, ma non ha un modo corretto di testarlo unitamente: https://github.com/symfony/symfony/issues/15098. –

+0

La difficoltà di testare EntityType deriva dalla classe che estende DoctrineType. DoctrineType viene fornito con un codice di codice troppo elevato come funzioni di unonymouse che fa tutta la magia. Trovo molto facile estendere il CoiceType, registrarlo come servizio e iniettare il repository piuttosto che usare EntityType. Provarlo è semplice, iniettare un DummyRepository. – albert

risposta

3

Ho faticato con il collaudo di unità qualcosa che si affida a un contenitore di servizi molto. All'inizio ho provato a deridere tutto, come hai fatto tu. Questo può far passare un test unitario con grande sforzo (i servizi hanno la tendenza a fare affidamento su altri servizi ancora in Symfony, che dovranno anche essere derisi), ma ci vuole ancora più impegno per assicurarsi che il test possa superare il test lavora con i dati con cui vuoi che funzioni.

Inoltre, l'unità di test di un database è notoriamente difficile e raramente discussa. Non sono sicuro che quello che sto condividendo sia la risposta "migliore", ma è una risposta che ha funzionato per me e aiuta a testare i servizi reali. In quanto tale, ho trovato che fosse un metodo più efficace per i test di quello che deride i servizi.

Questo è basato su un grande articolo, che, naturalmente, non riesco a individuare ora (aggiornerò questo se lo trovo per accreditarli).

Fondamentalmente, è possibile impostare i bundle in modo che i contenitori vengano testati.

composer.json:

"require-dev": { 
    "sensio/framework-extra-bundle": ">=3.0", 
    "symfony/asset": ">=3.2" 
} 

quindi creare un config.yml con tutti i servizi che potrebbe essere necessario e il minimo indispensabile per le forme Symfony:

framework: 
    secret: 'shh' 
    form: ~ 
    validation: { enable_annotations: true } 
    session: 
     storage_id: session.storage.mock_file 

doctrine: 
    # your doctrine settings if you want to test against the DB 

creare una classe AppKernel.

class AppKernel extends Kernel 
{ 
    public function registerBundles() 
    { 
     return array(
      new FrameworkBundle(), 
      new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(), 
      // any other bundles you need 
     ); 
    } 

    public function registerContainerConfiguration(LoaderInterface $loader) 
    { 
     $loader->load(__DIR__.'/config.yml'); 

    } 

    public function getLogDir() 
    { 
     return '/tmp/log/' . $this->environment; 
    } 
} 

Infine, creare una classe di supporto nel mio TestCase di base:

protected function getContainer() 
{ 
    if (!isset($this->kernel)) { 
     $this->kernel = new AppKernel('test', true); 
     $this->kernel->boot(); 
    } 
    if (!isset($this->container)) { 
     $this->container = $this->kernel->getContainer(); 
    } 
    return $this->container; 
} 

Ora è possibile accedere a tutti i servizi che sono stati registrati in questo modo:

public function testContainerAccess() 
{ 
    $this->assertTrue(is_object($this->getContainer()); 
    $this->assertTrue($this->getContainer()->get('doctrine.orm.entity_manager') instanceof \Doctrine\ORM\EntityManagerInterface); 
} 

test su un database è sempre difficile ed è una lattina separata di vermi. In questo caso, la cosa più semplice da fare probabilmente sarebbe creare uno schema di test separato ed eseguire le query su questo.

Spero che questo aiuti.

Problemi correlati