2014-06-06 8 views
14

Ich habe eine Frage zu Symfony FormType testen. http://symfony.com/doc/current/cookbook/form/unit_testing.htmlSymfony FormType Test Deal mit EntityType

In meinem Formulartyp die entity Art ist weit verbreitet. Das Testen der Formulartypen mit einem Dokumentinformations-Typ ist schrecklich.

Dies ist mein Formularfeld.

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 
    )); 
} 

Und hier ist der Spott für das Feld.

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; 
} 

Ist das wirklich der richtige Weg? Innerhalb der TypeTestCase habe ich keinen Zugriff auf irgendetwas, keinen Container, keinen Kernel, nichts. Dies macht das Testen eines Formulartyps ziemlich schwierig und frustrierend.

Gibt es eine bessere Möglichkeit, die Formulartypen zu testen? Oder eine einfachere Möglichkeit, mit Typen umzugehen, die eine ORM-Abhängigkeit haben?

Prost.

+2

Momentan unterstützt Symfony den EntityType out of the box, aber es gibt keinen geeigneten Weg, Unit-Test zu testen: https://github.com/symfony/symfony/issues/15098. –

+0

Die Schwierigkeit beim Testen des EntityType kommt von der Klasse DoctrineType. DoctrineType kommt mit zu viel Code als anonyme Funktionen, die die ganze Magie tut. Ich finde es sehr einfach, den CoiceType zu erweitern, ihn als Dienst zu registrieren und das Repository zu injizieren, anstatt EntityType zu verwenden. Testen Sie es einfach, injizieren Sie ein DummyRepository. – albert

Antwort

3

Ich hatte Probleme mit der Testeinheit, die auf einem Servicebehälter basiert. Zuerst habe ich versucht, alles zu verspotten, so wie du es getan hast. Dadurch kann ein Komponententest mit großem Aufwand bestanden werden (Dienste haben die Tendenz, sich auf noch andere Dienste in Symfony zu verlassen, die ebenfalls verspottet werden müssen), aber es erfordert noch mehr Anstrengung, um sicherzustellen, dass der Test bestanden wird arbeiten Sie mit den Daten, mit denen Sie arbeiten möchten.

Darüber hinaus ist das Testen von Einheiten in einer Datenbank notorisch schwierig und wird selten diskutiert. Ich bin mir nicht sicher, ob das, was ich teile, die "beste" Antwort ist, aber es ist eine Antwort, die für mich funktioniert hat und es hilft, die realen Dienste zu testen. Als solche habe ich festgestellt, dass es eine effektivere Methode zum Testen ist, als die Dienste zu verspotten.

Dies basiert auf einem tollen Artikel, den ich jetzt natürlich nicht finden kann (ich werde dies aktualisieren, wenn ich finde, dass es ihnen gutgeschrieben wird).

Grundsätzlich können Sie Ihre Bundles so einrichten, dass Container getestet werden.

composer.json:

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

Dann ein config.yml mit irgendwelchen Dienstleistungen erstellen Sie benötigen könnten und das absolute Minimum für Symfony Formen:

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 

Eine AppKernel Klasse.

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; 
    } 
} 

Schließlich schaffe ich eine Hilfsklasse in meiner Basis Testcase:

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; 
} 

Jetzt können Sie alle Dienste zugreifen, die Sie wie folgt registriert:

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

Prüfung gegen eine Datenbank ist immer schwierig und ist eine separate Dose Würmer. In diesem Fall wäre es wahrscheinlich am einfachsten, ein separates Testschema zu erstellen und Ihre Abfragen dagegen auszuführen.

Hoffe, das hilft.

Verwandte Themen