FOSUserBundle - PHPUnit - Макет пользователя

Я использую Symfony с FOSUserBundle, и теперь мне нравится тестировать такие вещи, как:

  • Жизненный цикл доктрины
  • Контроллер за брандмауэром

Для этих тестов мне нужно быть конкретным пользователем или, по крайней мере, в группе пользователей. Как мне издеваться над сеансом пользователя, чтобы...

  • Поле жизненного цикла, такое как «createdAt», будет использовать вошедшего в систему пользователя.
  • Контроллер действует так, как будто какой-то издевательский пользователь вошел в систему

Пример:

class FooTest extends ... {
    function setUp() {
        $user = $this->getMock('User', ['getId', 'getName']);

        $someWhereGlobal->user = $user;

        // after this you should be logged in as a mocked user
        // all operations should run using this user.
    }
}

person LeMike    schedule 22.02.2016    source источник


Ответы (3)


Вы можете сделать это с помощью LiipFunctionalTestBundle. После того, как вы установили и настроили Bundle, создать пользователя и войти в систему в тестах очень просто.

Создайте прибор для вашего пользователя

Это создает пользователя, который будет загружаться во время тестов:

<?php
// Filename: DataFixtures/ORM/LoadUserData.php

namespace Acme\MyBundle\DataFixtures\ORM;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\FixtureInterface;
use Doctrine\Common\Persistence\ObjectManager;
use Acme\MyBundle\Entity\User;

class LoadUserData extends AbstractFixture implements FixtureInterface
{
    public function load(ObjectManager $manager)
    {
        $user = new User();
        $user
            ->setId(1)
            ->setName('foo bar')
            ->setEmail('[email protected]')
            ->setPassword('12341234')
            ->setAlgorithm('plaintext')
            ->setEnabled(true)
            ->setConfirmationToken(null)
        ;
        $manager->persist($user);
        $manager->flush();

        // Create a reference for this user.
        $this->addReference('user', $user);
    }
}

Если вы хотите использовать группы пользователей, вы можете увидеть официальная документация.

Войдите как этот пользователь в свой тест

Как объясняется в документации LiipFunctionalTestBundle, вот как загрузить пользователя в базе данных и войдите в систему как этот пользователь:

/**
 * Log in as the user defined in the Data Fixture.
 */
public function testWithUserLoggedIn()
{
    $fixtures = $this->loadFixtures(array(
        'Acme\MyBundle\DataFixtures\ORM\LoadUserData',
    ));

    $repository = $fixtures->getReferenceRepository();

    // Get the user from its reference.
    $user = $repository->getReference('user')

    // You can perform operations on this user.
    // ...

    // And perform functional tests:

    // Create a new Client which will be logged in.
    $this->loginAs($user, 'YOUR_FIREWALL_NAME');
    $this->client = static::makeClient();

    // The user is logged in: do whatever you want.
    $path = '/';
    $crawler = $this->client->request('GET', $path);
}
person A.L    schedule 06.03.2016

Что бы я сделал в этом случае, так это создал CustomWebTestCase, который расширяет Symfony WebTestCase. В классе я бы создал метод, который выполняет аутентификацию для меня.

Вот пример кода:

namespace Company\MyBundle\Classes;

use Symfony\Bundle\FrameworkBundle\Client;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\BrowserKit\Cookie;
use Symfony\Component\Security\Core\Role\Role;
use Symfony\Component\Security\Core\User\User;

abstract class CustomWebTestCase extends WebTestCase
{

    /**
     * @param array|null $roles
     * @return \Symfony\Bundle\FrameworkBundle\Client
     */
    protected static function createAuthenticatedClient(array $roles = null) {
        // Assign default user roles if no roles have been passed.
        if($roles == null) {
            $role = new Role('ROLE_SUPER_ADMIN');
            $roles = array($role);
        } else {
            $tmpRoles = array();
            foreach($roles as $role)
            {
                $role = new Role($role, $role);
                $tmpRoles[] = $role;
            }
            $roles = $tmpRoles;
        }

        $user = new User('test_super_admin', 'passwd', $roles);

        return self::createAuthentication(static::createClient(), $user);
    }

    private static function createAuthentication(Client $client, User $user) {
        // Read below regarding config_test.yml!
        $session = $client->getContainer()->get('session');

        // Authenticate
        $firewall = 'user_area'; // This  MUST MATCH the name in your security.firewalls.->user_area<-
        $token = new UsernamePasswordToken($user, null, $firewall, $user->getRoles());
        $session->set('_security_'.$firewall, serialize($token));
        $session->save();

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

        return $client;
    }
}

Приведенный выше код напрямую создаст действительный сеанс пользователя и полностью пропустит брандмауэр. Поэтому вы можете создать любой $user, какой захотите, и он все равно будет действительным. Важная часть кода находится в методе createAuthentication. Вот что делает магия аутентификации.

Еще одна вещь, о которой стоит упомянуть — убедитесь, что вы установили framework.session.storage_id в session.storage.mock_file в своем config_test.yml, чтобы Symfony автоматически имитировала сеансы вместо того, чтобы вам приходилось иметь дело с этим в каждом тестовом случае:

framework:
    session:
        storage_id: session.storage.mock_file

Теперь в вашем тестовом случае вы просто расширите MyWebTestCase и вызовете метод createAuthenticatedClient():

class MyTest extends CustomWebTestCase {
    public function testSomething() {
        //Create authoried and unauthorized clients.
        $authenticatedClient = self::createAuthenticatedClient(array("ROLE_SUPER_ADMIN"));
        $unauthorizedClient = self::createAuthenticatedClient(array("ROLE_INSUFFICIENT_PERMISSIONS"));

        // Check if the page behaves properly when the user doesn't have necessary role(s).
        $unauthorizedClient->request('GET', '/secured-page');
        $response = $unauthorizedClient->getResponse();
        $this->assertFalse($response->isSuccessful());
        $this->assertEquals(403, $response->getStatusCode(), "This request should have failed!");

        // Check if the page behaves properly when the user HAS the necessary role(s)
        $authenticatedClient->request('GET', '/secured-page');
        $response = $authenticatedClient->getResponse();
        $this->assertTrue($response->isSuccessful());
        $this->assertEquals(200, $response->getStatusCode(), "This request should be working!");
    }
}

Вы также можете увидеть пример в официальной документации Symfony.

person tftd    schedule 06.03.2016
comment
Великолепно! Приведенный выше код напрямую создаст действительный сеанс пользователя и полностью пропустит брандмауэр. Вот так надо издеваться. Большое спасибо! :) - person LeMike; 06.03.2016

Вы можете легко сделать это с помощью LiipFunctionalTestBundle, который предоставляет вам множество ярлыков для создания модульного теста.

Если у вас уже есть пользователь формы для создания или редактирования, вы можете использовать его для пользователя рабочего процесса тестового модуля в своем приложении:

используйте метод makeClient для логирования теста

$credentials = array(
    'username' => 'a valid username',
    'password' => 'a valid password'
);

$client = static::makeClient($credentials);

используйте свою форму для проверки вашего творения

$crawler = $client->request('GET', '/profile');

$form = $crawler->selectButton('adding')->form();
$form['fos_user_profile_form[firstName]'] = 'Toto';
$form['fos_user_profile_form[lastName]'] = 'Tata';
$form['fos_user_profile_form[username]'] = 'dfgdgdgdgf';
$form['fos_user_profile_form[email]'] = '[email protected]';
$form['fos_user_profile_form[current_password]'] = 'gfgfgdgpk5dfgddf';

тестирование «createdAt» с помощью простого вызова findOneBy в пользователе репозитория, как это

$user = $this->getObjectManager()
             ->getRepository('AcmeSecurityBundle:User')
             ->findOneBy(array('username' => 'testCreateUserUsername'));

$this->assertTrue($user->getCreatedAt() == now());
person darkomen    schedule 22.02.2016
comment
Привет. Это решение, если у меня есть пользователь или учетные данные. Но у него всегда есть накладные расходы на вход через форму. Я ищу решение, в котором пользователь просто издевается или уже вошел в систему. Вопрос был обновлен с примером. - person LeMike; 23.02.2016