2012-12-03 6 views
5

Si è verificato un problema durante il tentativo di eseguire un test dell'unità basato su controller su un metodo controller che implementa Sessions.PHPUnità fallita con Symfony2 Sessions

In questo caso, qui è il metodo di controllo:

/** 
* @Route("/api/logout") 
*/ 
public function logoutAction() 
{ 
    $session = new Session(); 
    $session->clear(); 

    return $this->render('PassportApiBundle:Login:logout.html.twig'); 
} 

E il test funzionale:

public function testLogout() 
{ 
    $client = static::createClient(); 
    $crawler = $client->request('GET', '/api/logout'); 
    $this->assertTrue($client->getResponse()->isSuccessful()); 
} 

L'errore che viene prodotto:

Failed to start the session because headers have already been sent. (500 Internal Server Error)

ho provato inserendo $this->app['session.test'] = true; nel test, ma ancora non andare. Qualcuno ha provato a risolvere un problema come questo all'unità che testava un controller che utilizzava una sessione?

+1

Se si guarda il test per la classe 'Session' (https://github.com/symfony/symfony/blob/2.1/src/Symfony/Component/HttpFoundation/Tests/Session/SessionTest.php), sembra che dovresti iniettare un'istanza di 'MockArraySessionStorage' per evitare di iniziare la sessione. – Sven

+0

Ho impostato quelle linee, tuttavia, come faccio a passare a '$ client = static :: createClient();'? L'aggiunta di queste righe comporta lo stesso errore. –

+0

Sì, il problema è che il controller non offre l'iniezione di nulla. L'operazione 'new' non ha parametri e non ci sarebbe comunque modo di passare nulla dal test. Ma penso che Symfony 2 dovrebbe essere in grado di rendere utilizzabile il framework DI per questo. Hai letto per esempio questo: http://stackoverflow.com/questions/10106195/symfony-2-dependency-injection-di-of-controllers Inoltre, i documenti Symphony suggeriscono di arrivare alla Sessione in questo modo: '$ session = $ this-> getRequest() -> getSession(); '- questo potrebbe abilitare il bootstrap PHPUnit per usare gli oggetti di sessione fittizi – Sven

risposta

12

Prima di tutto è necessario utilizzare l'oggetto sessione dal contenitore. Quindi la tua azione dovrebbe essere più simile a:

/** 
* @Route("/api/logout") 
*/ 
public function logoutAction() 
{ 
    $session = $this->get('session'); 
    $session->clear(); 

    return $this->render('PassportApiBundle:Login:logout.html.twig'); 
} 

E quindi nel test puoi inserire il servizio nel "contenitore del cliente". Quindi:

public function testLogout() 
{ 
    $sessionMock = $this->getMockBuilder('Symfony\Component\HttpFoundation\Session') 
     ->setMethods(array('clear')) 
     ->disableOriginalConstructor() 
     ->getMock(); 

    // example assertion: 
    $sessionMock->expects($this->once()) 
     ->method('clear'); 

    $client = static::createClient(); 
    $container = $client->getContainer(); 
    $container->set('session', $sessionMock); 

    $crawler = $client->request('GET', '/api/logout'); 
    $this->assertTrue($client->getResponse()->isSuccessful()); 
} 

Con questo codice è possibile fare tutto ciò che si desidera con il servizio di sessione. Ma devi essere consapevole di due cose:

  • Questo simulatore verrà impostato SOLO per una richiesta (se desideri utilizzarlo nel prossimo, devi configurarlo nuovamente). È perché il client riavvia il kernel e ricostruisce il contenitore tra ogni richiesta.
  • movimentazione in Symfony 2.1 Session è poco diverso da quello Symfony 2

edit:

Ho aggiunto un'affermazione

+1

Grazie. Passare a '$ session = $ this-> get ('session')' ha funzionato perfettamente. Non so perché i documenti mi hanno detto di usare 'new Session()' sebbene ... http://symfony.com/doc/master/components/http_foundation/sessions.html –

1

qui solo per completare la risposta di Cipriano.

Come spiega Sven e quando si guarda il documento http://symfony.com/doc/2.3/components/http_foundation/session_testing.html di symfony, , è necessario installare la sessione di simulazione con un oggetto MockFileSessionStorage come primo argomento del costruttore.

è necessario utilizzare:

use Symfony\Component\HttpFoundation\Session\Storage\MockFileSessionStorage; 

E codice dovrebbe essere:

$sessionMock = $this->getMockBuilder('Symfony\Component\HttpFoundation\Session\Session') 
     ->setMethods(array('clear')) 
     ->disableOriginalConstructor() 
     ->setConstructorArgs(array(new MockFileSessionStorage())) 
     ->getMock(); 
+0

Potrebbe esserci un modo migliore esp con versione più recente di Symfony2 ma ho ancora bisogno di capire come - https://coderwall.com/p/newa2q/testing-with-sessions-symfony2 – Christian

6

Nel mio caso, è stato sufficiente per impostare

framework: 
    session: 
     storage_id: session.storage.mock_file 

nel config_test.yml. YMMV, e non ho un'idea di quello che sto facendo, ma funziona per me.

+0

ho già quell'impostazione in 'config_test.yml' di default, ma ho ottenuto 'Errore fatale: chiama ad una funzione membro get() su un non-oggetto' sulla riga' $ session-> get ('...'); 'dove' $ session' è da '$ session = $ this- > container-> get ('richiesta') -> getSession(); ' – Sithu