Reputation: 2180
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?
Upvotes: 5
Views: 8062
Reputation: 7281
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.
Upvotes: 8
Reputation: 61
Here just to complete Cyprian's response.
As Sven explains and when looking at the symfony's doc http://symfony.com/doc/2.3/components/http_foundation/session_testing.html, you have to instanciate the mock session with a MockFileSessionStorage object as first constructor argument.
You need to use :
use Symfony\Component\HttpFoundation\Session\Storage\MockFileSessionStorage;
And code should be :
$sessionMock = $this->getMockBuilder('Symfony\Component\HttpFoundation\Session\Session')
->setMethods(array('clear'))
->disableOriginalConstructor()
->setConstructorArgs(array(new MockFileSessionStorage()))
->getMock();
Upvotes: 2
Reputation: 11364
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:
edit:
I've added an assertion
Upvotes: 13