简体   繁体   English

PHPUnit失败了Symfony2 Sessions

[英]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. 尝试在实现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) (500内部服务器错误)

I've tried placing in $this->app['session.test'] = true; 我试过放入$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? 有没有人尝试解决这样的问题来对使用会话的控制器进行单元测试?

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 Symfony 2.1中的会话处理与Symfony 2略有不同

edit: 编辑:

I've added an assertion 我添加了一个断言

In my case, it was enough to set 在我的情况下,它足以设置

framework:
    session:
        storage_id: session.storage.mock_file

in the config_test.yml . config_test.yml YMMV, and I don't have that much of an idea what I'm actually doing, but it works for me. YMMV,我没有那么多想法,我实际上在做什么,但它对我有用。

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. 正如Sven解释并在查看symfony的文档http://symfony.com/doc/2.3/components/http_foundation/session_testing.html时 ,您必须使用MockFileSessionStorage对象将模拟会话实例化为第一个构造函数参数。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM