2014-06-16 10 views
6

Mentre iniziamo ad usare Symfony 2 su diversi progetti ora, scopriamo che c'è un bel po 'di codice che potremmo condividere tra i nostri progetti. Quindi abbiamo iniziato a estrarre le funzionalità nei bundle di Symfony 2 per condividerle tra i nostri progetti.Come testare un pacchetto Symfony 2 condiviso senza un progetto completo

Mentre fondamentalmente le cose funzionano, restano alcune domande che non sono facilmente consultabili, specialmente quando si tratta di testare il pacchetto condiviso.

Il primo piccolo gruppo che abbiamo estratto contiene un'entità Doctrine, una kernel.event_listener che viene auto-iniettata nel contenitore DI del progetto client, un'annotazione, un altro servizio e un paio di comandi. L'idea di base è che il progetto client possa annotare i suoi controllori con la nostra annotazione, l'event_listener intercetterà le richieste ai controllori annotati ed eseguirà una logica aggiuntiva (che coinvolge l'entità della dottrina) prima che il controllore venga infine richiamato. I comandi hanno lo scopo di amministrare le voci del database dell'entità doctrine.

Finora, tutto funziona esattamente come ci aspettavamo, ma stiamo lottando solo con la testabilità del bundle. Prima di tutto, il repository Git che contiene il bundle non contiene un progetto Symfony2 completo. Sarebbe eccessivo visto che stiamo costruendo un pacchetto solo qui, non un'intera applicazione, giusto?

Ma come possiamo testare l'ascoltatore di eventi? Come possiamo testare che venga iniettato nel contenitore DI? Avremmo bisogno di un controller di test che verrà annotato con la nostra annotazione speciale, in modo che possiamo verificare che il nostro listener di eventi lo acquisisca correttamente. Il controller deve essere sempre disponibile solo durante il test e non deve mai essere visualizzato in alcuna applicazione client.

Come possiamo testare i comandi? Avremmo bisogno di prendere in giro il database dietro la dottrina. Quando cerchiamo di eseguire il comando in un test phpunit che è semplicemente bootstrap con /vendor/autoload.php, naturalmente otteniamo:

Fatal error: Call to undefined method Symfony\Component\Console\Application::getKernel() in /.../vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Command/ContainerAwareCommand.php on line 3

Così ci si sente come stiamo andando finire che necessitano di un intero progetto Symfony2 in repository del nostro pacchetto in ogni caso in per poter eseguire il bootstrap dell'intero framework per poter eventualmente testare i nostri componenti. Quando ho guardato i bundle Symfony2 open source, non ho trovato nessuno che avesse l'intero Framework controllato nei loro repository Git, così che comunque si sentisse sbagliato.

Cosa mi manca? C'è un pezzo di documentazione sullo sviluppo bundle di solo bundle/applicationless che mi manca?

Edit:

ho trovato una soluzione per il test dei comandi qui: http://www.ricardclau.com/2013/02/testing-symfony2-commands-mocking-the-di-container-with-mockery/

Si è scoperto l'errore è venuto da ContainerAwareCommand cercando di creare un nuovo contenitore, che ovviamente non avrebbe funzionato in un ambiente di test a nudo . Ho risolto il problema deridendo contenitore e parenterale in Command manualmente in questo modo:

use Symfony\Component\Console\Application; 
use Symfony\Component\Console\Tester\CommandTester; 

class MyCommandTest extends \PHPUnit_Framework_TestCase { 

    public function testExecute() { 
     $application = new Application(); 
     $application->add(new MyCommand()); 

     $command = $application->find('my:command'); 
     $command->setContainer($this->getMockContainer()); // <= This avoids ContainerAwareCommand creating a 'real' container in a test env 
     $commandTester = new CommandTester($command); 
     $commandTester->execute(array('command' => $command->getName())); 

     print $commandTester->getDisplay(); 

     $this->assertRegExp('/.../', $commandTester->getDisplay()); 
    } 

    protected function getMockContainer() { 
     // Mock the container and everything you'll need here 
     $mockDoctrine = $this->getMock('Symfony\Bridge\Doctrine\RegistryInterface'); 
     $mockDoctrine->...; 

     $mockContainer = $this->getMock('Symfony\Component\DependencyInjection\Container'); 
     $mockContainer->expects($this->once()) 
         ->method('get') 
         ->with('doctrine') 
         ->willReturn($mockDoctrine); 
     return $mockContainer; 
    } 
} 

Credo test controllore dovrà lavorare in un simile, finto-pesante, modo. Quando troverò una soluzione, invierò qui una risposta completa ...

+0

io non sono davvero un esperto (non troppo tempo per sperimentare e troppo lavoro), ma penso che avete bisogno solo un sottoinsieme di dipendenze come framework-bundle, console, http-kernel per configurare ed eseguire i test. – gremo

+0

Forse la tua modifica dovrebbe essere una risposta ... Comunque, buon punto di partenza. Grazie! – Aerendir

risposta

0

Questa domanda è piuttosto vecchia, ma mi sono imbattuta in essa.

I bundle sono un modo specifico di Symfony per condividere intere librerie incl. la loro rispettiva configurazione del contenitore di iniezione di dipendenza.

Pertanto, i bundle dipendono dal kernel Symfony e se un bundle dipende da un altro bundle, si creano dipendenze pesanti che impediscono in modo efficace il test dell'unità: Per testare un'unità (una classe) nel bundle A, è necessario il pacchetto B più il kernel Symfony.

È ancora possibile eseguire il test, ma i test risultanti sono test di accettazione/integrazione, non test di unità. Quelli non sono adatti per lo sviluppo guidato da test, lento e fragile, come già notato.

Aggiornamento

ho appena scritto un post su questo blog: https://lastzero.net/2015/11/dependent-symfony-2-bundles-and-testability/