2012-12-03 59 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