問題描述
Symfony 2.8 WebTestCase:無法創建登錄會話 (Symfony 2.8 WebTestCase: Cannot create logged‑in session)
我目前正在對基於 symfony 2.8 的管理區域進行單元測試。所以我為儀表板寫了一個小的基本測試:測試檢查
a)如果用戶當前沒有登錄,應該有一個重定向到登錄頁面。
b) 如果用戶已登錄,則應顯示儀表板。
為了“登錄”用戶(= 創建活動會話),我想出了一個基於在 symfony 文檔中的相應食譜文章中:How to Simulate Authentication with a Token in a Functional測試
但這似乎不起作用。我最初的測試失敗了。因此,我向僅打印出會話信息的虛擬控制器添加了另一個請求。這表明雖然似乎設置正確,但當前用戶信息和安全令牌存儲似乎不正確 ‑ 因為我得到默認的“AnonymousToken”和 getUser 方法的空返回。
這裡是我的測試代碼:
<?php
namespace GOC\Bundle\AdminBundle\Tests\Controller;
use FOS\RestBundle\Util\Codes;
use Symfony\Bundle\FrameworkBundle\Client;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\BrowserKit\Cookie;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\NullOutput;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use GOC\Bundle\FrameworkBundle\Model\ContextInterface;
use GOC\Bundle\FrameworkBundle\Tests\WebTestCase;
class DashboardControllerTest extends WebTestCase
{
const BASE_URL = '';
/**
* @var ContextInterface|null
*/
protected $context;
public static function setUpBeforeClass()
{
$client = static::createClient([
'environment' => 'test',
'debug' => false,
], [
'HTTP_HOST' => 'demo‑cms.dev',
]);
$container = $client‑>getContainer();
$kernel = $container‑>get('kernel');
$application = new Application($kernel);
$application‑>setAutoExit(false);
$input = new ArrayInput(array(
'command' => 'doctrine:mongodb:fixtures:load',
));
$output = new NullOutput();
$application‑>run($input, $output);
}
/**
* Testing whether the backend is not publicly accessible
*/
public function testFirewallRedirect()
{
$client = static::createClient();
$client‑>request('GET', $this‑>buildUrl('/admin/dashboard'));
$response = $client‑>getResponse();
$this‑>assertTrue($client‑>getResponse()‑>isRedirect($this‑>buildUrl('http://localhost/admin/login')));
$crawler = $client‑>request('GET', $response‑>headers‑>get('location'));
$this‑>assertEquals(
1,
$crawler‑>filter('html:contains("Willkommen")')‑>count()
);
}
/**
* Testing whether the backend is not publicly accessible
*/
public function testFirewallAccess()
{
$client = static::createClient([
'environment' => 'test',
'debug' => false,
], [
'HTTP_HOST' => 'demo‑cms.dev',
]);
$this‑>logIn($client);
$client‑>request('GET', $this‑>buildUrl('/admin/dashboard'));
$response = $client‑>getResponse();
// This fails...
//$this‑>assertEquals(Codes::HTTP_OK, $response‑>getStatusCode());
// Debug statements
$client‑>request('GET', $this‑>buildUrl('/forgot‑password‑sent'));
$response = $client‑>getResponse();
dump($response);
}
/**
* @param Client $client
*/
protected function logIn(Client $client)
{
$container = $client‑>getContainer();
$repository = $container‑>get('goc_account.user_manager')‑>getRepository();
$user = $repository‑>getUserByUsername('admin@gardenofconcepts.com', $this‑>getContext($client));
$firewall = 'main';
$token = new UsernamePasswordToken($user, null, $firewall, $user‑>getRoles());
$container‑>get('security.token_storage')‑>setToken($token);
$session = $container‑>get('session');
// Saw this somewhere else, makes no difference though
//$session = new Session(new MockArraySessionStorage());
//$session‑>start();
//$container‑>set('session', $session);
$session‑>set('_security_'.$firewall, serialize($token));
$session‑>save();
$cookie = new Cookie($session‑>getName(), $session‑>getId());
$client‑>getCookieJar()‑>set($cookie);
}
/**
* @param $url
*
* @return string
*/
protected function buildUrl($url)
{
return $this::BASE_URL . $url;
}
/**
* @param Client $client
*
* @return ContextInterface
*/
protected function getContext(Client $client)
{
if ($this‑>context) {
return $this‑>context;
}
$this‑>context = $client‑>getContainer()‑>get('goc_framework.context_manager')‑>getContextByName('demo');
return $this‑>context;
}
}
提前感謝您的幫助 ‑ 非常感謝!
參考解法
方法 1:
We are not trying to mock the token but actually create one with the following function (which might be adaptable to your situation):
protected function createAuthenticatedClient($username, $password)
{
$client = static::createClient();
$client‑>request(
'POST',
'/api/v1/login_check',
array(
'username' => $username,
'password' => $password,
)
);
$data = json_decode($client‑>getResponse()‑>getContent(), true);
$client = static::createClient();
$client‑>setServerParameter('HTTP_Authorization', sprintf('Bearer %s', $data['token']));
return $client;
}
After using this like
$client = $this‑>createAuthenticatedClient('user', 'password');
every request sent will be attached with our actual Bearer.