Имитация аутентификации в Symfony 2 / Doctrine без вызовов базы данных в функциональных тестах

1

Я пытаюсь написать некоторые функциональные тесты для своего приложения, проблема, с которой я сталкиваюсь, заключается в том, что, если я не вытащил пользователя из базы данных, я не могу заставить его использовать новый пользовательский объект. Я хотел бы как можно больше сократить количество запросов к базе данных.

Все мои пользователи хранятся в базе данных и доступны через уровень 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('[email protected]');

$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.

Любые предложения вокруг этого были бы блестящими :)

Теги:
doctrine2
functional-testing

1 ответ

0

Это связано с тем, что пользовательский провайдер будет каждый раз обновлять пользователя с помощью UserProviderInterface :: refreshUser(), хотя он доступен в сеансе.

Это поведение по умолчанию, поскольку данные пользователя могут быть изменены с момента последнего чтения из базы данных. Изменение этого поведения потребует внедрения пользовательского провайдера на данный момент (см. Https://github.com/symfony/symfony/issues/1338).

Самое простое исправление - добавить идентификатор пользователя. Если я прочитаю вашу конфигурацию, вы использовали электронное письмо как идентификатор:

$user = new User();
$user->setRoles(['ROLE_ADMIN']);
$user->setEmail('[email protected]');

Symfony сделает запрос к базе данных, но он также сделает запрос в реальном сценарии. Если вы хотите изменить это поведение, вам необходимо предоставить собственную реализацию UserProviderInterface, которая не будет делать запрос по каждому запросу.

В качестве альтернативы, используйте другие методы проверки подлинности (например, http basic) с функциональными тестами.

  • 0
    Ах, хорошо, если он делает вызов БД независимо (с использованием UserProvider по умолчанию), тогда мне лучше интегрировать базовую аутентификацию HTTP для функционального тестирования?

Ещё вопросы

Сообщество Overcoder
Наверх
Меню