Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHPUnit failing with Symfony2 Sessions

I'm running into an issue when trying to run a controller based unit test on a controller method that implements Sessions.

In this case, here is the controller method:

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

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

And the functional test:

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

The error that is produced:

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

I've tried placing in $this->app['session.test'] = true; into the test, but still no go. Has anyone tried resolving an issue like this to unit testing a controller that uses a session?

like image 319
Steven Lu Avatar asked Dec 03 '12 23:12

Steven Lu


2 Answers

First of all you should use session object from container. So your action should look more like:

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

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

And then in your test you can inject service into "client's container". So:

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

With this code you can do everything you want with your session service. But You have to be aware two things:

  • This mock will be set ONLY for one request (if you want use it in next one, you should set up it again). It's because the client restart kernel and rebuild container between each request.
  • Session handling in Symfony 2.1 is little different than Symfony 2

edit:

I've added an assertion

like image 171
Cyprian Avatar answered Oct 20 '22 22:10

Cyprian


In my case, it was enough to set

framework:
    session:
        storage_id: session.storage.mock_file

in the config_test.yml. YMMV, and I don't have that much of an idea what I'm actually doing, but it works for me.

like image 27
scy Avatar answered Oct 20 '22 23:10

scy