在功能测试中在没有数据库调用的情况下模拟Symfony 2 / Doctrine中的身份验证

时间:2015-07-06 16:39:30

标签: php symfony doctrine-orm functional-testing

我试图为我的应用程序编写一些功能测试,我遇到的问题是,除非我真的将用户从数据库中拉出来,否则我无法使用新的用户对象。我希望尽可能减少数据库查询量。

我的所有用户都存储在数据库中,并通过Doctrine层访问。以下是我的安全设置以及当前的工作原理:

// app/security.yml

security:
providers:
    administrators:
        entity: { class: User, property: email }

encoders:
    User:
        algorithm: sha512

role_hierarchy:
    ROLE_ADMIN: ROLE_USER

firewalls:
    dev:
       pattern: ^/(_(profiler|wdt|error)|css|images|js)/
       security: false

    default:
        anonymous: ~
        http_basic: ~
        form_login:
            login_path: login
            check_path: login-check
            csrf_provider: security.csrf.token_manager
        logout:
            path: /logout
            target: login

access_control:
    - { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/, role: ROLE_ADMIN }

通过关注http://symfony.com/doc/current/cookbook/testing/simulating_authentication.html,我有以下工作

$client = static::createClient();
$user = $client->getContainer()->get('doctrine')->getEntityManager()->getRepository('User')->findOneByEmail('nick@example.com');

$session = $client->getContainer()->get('session');

$firewall = 'default';
$token = new UsernamePasswordToken($user, null, $firewall, $user->getRoles());
$session->set('_security_'.$firewall, serialize($token));
$session->save();

$cookie = new Cookie($session->getName(), $session->getId());
$client->getCookieJar()->set($cookie);

$crawler = $client->request('GET', '/some-secure-url');

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

我希望能够做到的是:

$client = static::createClient();
$user = new User();
$user->setRoles(['ROLE_ADMIN']);

$session = $client->getContainer()->get('session');

$firewall = 'default';
$token = new UsernamePasswordToken($user, null, $firewall, $user->getRoles());
$session->set('_security_'.$firewall, serialize($token));
$session->save();

$cookie = new Cookie($session->getName(), $session->getId());
$client->getCookieJar()->set($cookie);

$crawler = $client->request('GET', '/some-secure-url');

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

但是目前当我尝试这种方法时,我得到以下内容

You cannot refresh a user from the EntityUserProvider that does not contain an identifier. The user object has to be serialized with its own identifier mapped by Doctrine.

对此有任何建议都很棒:)

1 个答案:

答案 0 :(得分:0)

这是因为用户提供商每次都会尝试使用UserProviderInterface::refreshUser()刷新用户,即使会话中有该用户。

这是默认行为,因为用户详细信息可能自上次从数据库中读取后发生了更改。更改此行为需要此时实现自定义用户提供程序(请参阅https://github.com/symfony/symfony/issues/1338)。

最简单的解决方法是为用户添加标识符。如果我阅读了您的配置,您已使用电子邮件作为标识符:

$user = new User();
$user->setRoles(['ROLE_ADMIN']);
$user->setEmail('foo@bar.com');

Symfony将对数据库进行查询,但它也会在真实场景中进行查询。如果您想要更改此行为,则需要provide your own implementation of the UserProviderInterface,这不会对每个请求进行查询。

或者,使用其他身份验证方法(如http basic)和功能测试。