2012-12-03 75 views
5

我试图在实现会话的控制器方法上运行基于控制器的单元测试时遇到问题。PHPUnit与Symfony2会话失败

在这种情况下,这里是控制器方法:

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

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

和功能测试:

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

我试着:

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

所产生的误差置入$this->app['session.test'] = true;进入测试,但仍然没有去。有没有人试图解决这样的问题来单元测试使用会话的控制器?

+1

如果你看一下'Session'类的测试(https://github.com/symfony/symfony/blob/2.1/src/Symfony/Component/HttpFoundation/Tests/Session/SessionTest.php),它看起来应该注入一个'MockArraySessionStorage'实例来避免启动会话。 – Sven

+0

我设置了这些行,但是,如何将它传递给'$ client = static :: createClient();'?单独添加这些行会导致相同的错误。 –

+0

是的,问题是您的控制器不提供任何注入。 'new'操作没有参数,并且无论如何都无法传递测试中的任何内容。但我认为Symfony 2应该能够使它成为可用于此的DI框架。你有没有读过这样的例子:http://stackoverflow.com/questions/10106195/symfony-2-dependency-injection-di-of-controllers另外,Symphony文档建议像这样进入Session:'$ session = $ this-> getRequest() - > getSession();' - 这可以使PHPUnit引导使用模拟会话对象 – Sven

回答

12

首先,您应该使用容器中的会话对象。所以,你的行动应该更像:

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

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

然后在您的测试,你可以注入到服务“客户端的容器”。所以:

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

有了这个代码,你可以做你想做你的会话服务的一切。但你必须知道两件事:

  • 这个模拟将只设置一个请求(如果你想在下一个使用它,你应该再次设置它)。这是因为客户端在每个请求之间重新启动内核并重建容器。
  • 会话中的Symfony 2.1处理比Symfony的2有点不同

编辑:

我已经添加了一个断言

+1

谢谢。更改为'$ session = $ this-> get('session')'使它完美工作。我不知道为什么文档告诉我使用'新会话()'虽然... http://symfony.com/doc/master/components/http_foundation/sessions.html –

1

这里只是为了完成塞浦路斯的响应。

正如Sven解释的那样,在看symfony的文档http://symfony.com/doc/2.3/components/http_foundation/session_testing.html, 时,必须使用MockFileSessionStorage对象作为第一个构造函数参数来实例化模拟会话。

您需要使用:

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

和代码应该是:

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

有可能是一个更好的方法ESP更新版本的Symfony2,但我仍然需要弄清楚 - https://coderwall.com/p/newa2q/testing-with-sessions-symfony2 – Christian

6

对我来说,这已经足够了设置

framework: 
    session: 
     storage_id: session.storage.mock_file 

config_test.yml。 YMMV,我没有那么多的想法,我实际上在做什么,但它适用于我。

+0

默认情况下,我已经在'config_test.yml'中设置了该设置,但是我得到了'致命的错误:在'$ session-> get('...')行''调用一个非对象的成员函数get()''''''$ session'$ this- >容器 - >得到( '请求') - >的getSession();' – Sithu