Symfony2 - 使用 FOSUserBundle 进行测试

Posted

技术标签:

【中文标题】Symfony2 - 使用 FOSUserBundle 进行测试【英文标题】:Symfony2 - Tests with FOSUserBundle 【发布时间】:2013-02-04 03:40:24 【问题描述】:

我会用 FOSUserBundle 为 Symfony2 编写一个测试。

目前我尝试了一些方法,但没有一个有效。

我需要一个类似“createAuthClient”的函数。

这是我的基础课。 我发布它是因为您可以更好地理解我的问题。

<?php
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\BrowserKit\Cookie;

class WebTestMain extends WebTestCase

    protected static $container;

    static protected function createClient(array $options = array(), array $server = array())
    
        $client = parent::createClient($options, $server);

        self::$container = self::$kernel->getContainer();

        return $client;
    

    static function createAuthClient(array $options = array(), array $server = array())
    
        // see lines below with my tries
    

第一次尝试:

if(static::$kernel === null)

    static::$kernel = static::createKernel($options);
    static::$kernel->boot();

if(static::$container === null)

    self::$container = self::$kernel->getContainer();


$parameters = self::$container->getParameter('test');
$server = array_merge(array('HTTP_HOST' => $parameters['host'], 'HTTP_USER_AGENT' => $parameters['useragent']), $server);

$client = self::createClient($options, $server);

$userProvider = self::$container->get('fos_user.user_manager');
$user = $userProvider->findUserBy(array('id' => 1));
$client->getCookieJar()->set(new Cookie('MOCKSESSID', true));
$session = self::$kernel->getContainer()->get('session');
$token = new UsernamePasswordToken($user, null, 'main', $user->getRoles());
$client->getContainer()->get('security.context')->setToken($token);
$session->set('_security_main', serialize($token));

return $client;

然后我搜索并搜索...... 我的第二次尝试。

if(static::$kernel === null)

    static::$kernel = static::createKernel($options);
    static::$kernel->boot();

if(static::$container === null)

    self::$container = self::$kernel->getContainer();


$parameters = self::$container->getParameter('test');
$server = array_merge(
    array(
        'HTTP_HOST' => $parameters['host'],
        'HTTP_USER_AGENT' => $parameters['useragent'],
        'PHP_AUTH_USER' => 'admin',
        'PHP_AUTH_PW'   => 'admin'
    ),
    $server
);
$client = static::createClient(array(), array());
$client->followRedirects();
return $client;

这是我发布这个问题之前的最后一次尝试......

$client = self::createClient($options, $server);

$parameters = self::$container->getParameter('test');
$server = array_merge(
    array(
        'HTTP_HOST' => $parameters['host'],
        'HTTP_USER_AGENT' => $parameters['useragent']
    ),
    $server
);

$client->setServerParameters($server);

$usermanager = self::$container->get('fos_user.user_manager');
$testuser = $usermanager->createUser();
$testuser->setUsername('test');
$testuser->setEmail('test@mail.org');
$testuser->setPlainPassword('test');
$usermanager->updateUser($testuser);

return $client;

在此先感谢您。

【问题讨论】:

【参考方案1】:

我发现使用经过身份验证的用户进行测试的最佳方法是访问您的登录页面并使用您从夹具加载的用户名和密码提交表单。这可能看起来缓慢而繁琐,但会测试用户实际会做什么。您甚至可以创建自己的方法来快速轻松地使用它。

public function doLogin($username, $password) 
   $crawler = $this->client->request('GET', '/login');
   $form = $crawler->selectButton('_submit')->form(array(
       '_username'  => $username,
       '_password'  => $password,
       ));     
   $this->client->submit($form);

   $this->assertTrue($this->client->getResponse()->isRedirect());

   $crawler = $this->client->followRedirect();

【讨论】:

帮了我:) 谢谢+1 @Michael:你能告诉我如何验证登录用户吗,因为如果我们输入错误的密码,也会发生重定向。和 $this->assertTrue($this->client->getResponse()->isRedirect());这似乎在两个方面都有效 @Code 您可以断言重定向后的响应包含您在主页中的某些内容,或者它不包含登录页面中的某些内容(请参阅编辑后的答案)。您还可以在重定向发生之前使用相同的方法验证重定向发送给您的 url!【参考方案2】:

创建AbstractControllerTest 并在setUp() 上创建授权客户端,如下所示:

<?php
// ...
use Symfony\Component\BrowserKit\Cookie;

abstract class AbstractControllerTest extends WebTestCase

    /**
     * @var Client
     */
    protected $client = null;


    public function setUp()
    
        $this->client = $this->createAuthorizedClient();
    

    /**
     * @return Client
     */
    protected function createAuthorizedClient()
    
        $client = static::createClient();
        $container = $client->getContainer();

        $session = $container->get('session');
        /** @var $userManager \FOS\UserBundle\Doctrine\UserManager */
        $userManager = $container->get('fos_user.user_manager');
        /** @var $loginManager \FOS\UserBundle\Security\LoginManager */
        $loginManager = $container->get('fos_user.security.login_manager');
        $firewallName = $container->getParameter('fos_user.firewall_name');

        $user = $userManager->findUserBy(array('username' => 'REPLACE_WITH_YOUR_TEST_USERNAME'));
        $loginManager->loginUser($firewallName, $user);

        // save the login token into the session and put it in a cookie
        $container->get('session')->set('_security_' . $firewallName,
            serialize($container->get('security.context')->getToken()));
        $container->get('session')->save();
        $client->getCookieJar()->set(new Cookie($session->getName(), $session->getId()));

        return $client;
    
 

注意:请用您的测试用户名替换用户名。

然后,扩展AbstractControllerTest 并使用全局$client 发出如下请求:

class ControllerTest extends AbstractControllerTest

    public function testIndexAction()
    
        $crawler = $this->client->request('GET', '/admin/');

        $this->assertEquals(
            Response::HTTP_OK,
            $this->client->getResponse()->getStatusCode()
        );
    

此方法经过测试,效果很好

【讨论】:

@k0pernikus 在我的示例中我没有使用任何命名空间,因此它隐式使用全局命名空间,不需要使用语句。 我发现显式依赖比隐式约定好很多次。 (我写这篇评论的事实应该很明显。)在我当前的项目中,我有一堆来自不同第三方包的Client 类。我不得不查看和测试,直到意识到Symfony\Component\BrowserKit\Client 是正确的。您的答案虽然提供了一个很好的工作示例,但如果它包含 use 语句会更有用。到目前为止,仍然需要手动工作来找出解决方案。 @Paolo Stefan:如果它不起作用,那是因为 Symfony 2.6 及更高版本中的模拟会话存储存在一个未解决的问题:github.com/symfony/symfony/issues/13450。升级后,我们不得不切换到 Michael Smith 的答案(使用客户端/爬虫登录、跟踪重定向等)。 这项技术看起来不错,但在 Symfony 3 中不起作用(至少不像我留下此评论的那种类型)。 Michael Smith 编写的技术效果很好。

以上是关于Symfony2 - 使用 FOSUserBundle 进行测试的主要内容,如果未能解决你的问题,请参考以下文章

Symfony2:如何对自定义复合表单类型使用约束?

FOSUserBundle 使用电子邮件登录 (Symfony2)

Symfony2:使用侦听器更改渲染视图

使用多个参数对对象进行排序 - symfony2

symfony2:使用 fosuserbundle 登录后使用引用

在 Symfony2 中使用 GenemuFormBundle