Вход в Symfony2 FOS UserBundle в функциональных тестах - PullRequest
9 голосов
/ 07 февраля 2012

Как войти в тесты, чтобы иметь возможность выполнять пользовательские действия?

Ответы [ 5 ]

5 голосов
/ 24 августа 2012

На самом деле аутентификация должна выполняться так, как это делает настоящий пользователь. В этом случае вы должны знать простой пароль и заполнить форму авторизации

use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class XXX extends WebTestCase {
  public function testUserLogin() {

   $client = static::createClient();
   $crawler = $client->request('GET', '/login');

   $form = $crawler->selectButton('_submit')->form(array(
     '_username'  => 'user',
     '_password'  => 'pa$$word',
   ));

   $client->submit($form);
   $crawler = $client->followRedirect(); // "/" page

   // if credentials were correct, you should be logged in and ready to test your app
  }
}
4 голосов
/ 30 августа 2013

Существующие ответы на этот вопрос были полезны, но ни один из них не решил мою проблему напрямую. Я использую Symfony 2.3.

Вот мое решение:

<?php

namespace CDE\TestBundle\Base;

use FOS\UserBundle\Model\User;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Component\BrowserKit\Cookie;
use Symfony\Component\BrowserKit\CookieJar;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Storage\MockFileSessionStorage;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;

class BaseUserTest extends WebTestCase {

    protected $client;
    protected $container;
    protected $storage;
    protected $session;
    protected $user;
    protected $cookieJar;
    protected $cookie;
    protected $token;

    public function __construct() {
        $this->client = static::createClient();
        $this->container = $this->client->getContainer();
        $this->storage = new MockFileSessionStorage(__dir__.'/../../../../app/cache/test/sessions');
        $this->session = new Session($this->storage);

    }

    public function getUserManager() {
        return $this->container->get('cde_user.manager.user');

    }

    public function getSecurityManager() {
        return $this->container->get('fos_user.security.login_manager');

    }

    public function getUser($role = null) {
        if (!isset($this->user)) {
            $user = $this->getUserManager()->loadByUsername('user');

            if (isset($user)) {
                $this->user = $user;
            } else {
                $this->user = $this->getUserManager()->create();

                $this->user->setEnabled(true);
                $this->user->setUsername('user');
                $this->user->setEmail('user@quiver.is');
                $this->user->setPlainPassword('user');
                $this->getUserManager()->updatePassword($this->user);
                if (isset($role)) {
                    $this->user->addRole($role);
                }
                $this->getUserManager()->add($this->user);
            }

        }

        return $this->user;
    }

    public function logIn(User $user, Response $response) {
        $this->session->start();

        $this->cookie = new Cookie('MOCKSESSID', $this->storage->getId());
        $this->cookieJar = new CookieJar();
        $this->cookieJar->set($this->cookie);
        $this->token = new UsernamePasswordToken($user, 'user', 'main', $user->getRoles());
        $this->session->set('_security_main', serialize($this->token));


        $this->getSecurityManager()->loginUser(
            $this->container->getParameter('fos_user.firewall_name'),
            $user,
            $response
        );

        $this->session->save();
    }

    public function removeUser(User $user) {

    }
}

RestControllerTest.php

<?php

namespace CDE\ContentBundle\Tests\Controller;

use CDE\TestBundle\Base\BaseUserTest;
use Symfony\Component\HttpFoundation\Response;

class RestControllerTest extends BaseUserTest
{
    protected $comment;

    public function __construct() {
        parent::__construct();
        $this->logIn($this->getUser('ROLE_ADMIN'), new Response());

    }

    public function getGalleryManager() {
        return $this->container->get('cde_content.manager.gallery');
    }

    public function getAWSManager() {
        return $this->container->get('cde_utility.manager.aws');
    }

    public function createGallery()
    {
        //        Copy test.jpeg into the web folder
        $filename = 'gallery/user-test.jpg';
        copy(__DIR__.'/../Mock/test.jpeg', __DIR__.'/../../../../../web/'.$filename);
        $this->getAWSManager()->copyGalleryFile($filename);


        $gallery = $this->getGalleryManager()->create();
        $gallery->setUser($this->getUser());
        $gallery->setFilename($filename);
        $gallery->setTitle('test gallery');
        $gallery->setDescription('test gallery description');
        $gallery->setMarked(false);
        $this->getGalleryManager()->add($gallery);
        $this->assertEquals($gallery->getMarked(), false);
    }

    public function createComment()
    {
        $galleries = $this->getGalleryManager()->findByUser($this->getUser());
        $gallery = $galleries[0];

        $client = static::createClient();
        $client->getCookieJar()->set($this->cookie);
//        $client = static::createClient(array(), new History(), $cookieJar);

        $crawler = $client->request('POST', 'api/createComment/'.$gallery->getId(), array(
            'comment' => 'testing testing 123',
            'marked' => 'false'
        ));

        $response = $client->getResponse();
        $this->comment = json_decode($response->getContent());
        $this->assertEquals($this->comment->comment, 'testing testing 123');
        $this->assertFalse($this->comment->marked);
        $this->assertEquals($response->getStatusCode(), 200);
    }

    public function getComment()
    {
        $client = static::createClient();

        $crawler = $client->request('GET', 'api/getComment/'.$this->comment->id);

        $response = $client->getResponse();
        $comment = json_decode($response->getContent());
        $this->assertEquals($comment->comment, 'testing testing 123');
        $this->assertFalse($comment->marked);
        $this->assertEquals($response->getStatusCode(), 200);

    }

    public function updateComment()
    {
        $client = static::createClient();

        $crawler = $client->request('GET', 'api/updateComment');
    }

    public function deleteComment()
    {
        $client = static::createClient();

        $crawler = $client->request('DELETE', 'api/deleteComment');
    }

    public function getComments()
    {
        $client = static::createClient();

        $crawler = $client->request('GET', 'api/getComments');
    }

    public function getGalleries()
    {
        $client = static::createClient();

        $crawler = $client->request('GET', 'api/getGalleries');
    }

    public function removeGallery() {
        $galleries = $this->getGalleryManager()->findByUser($this->getUser());
        foreach ($galleries as $gallery) {
            $this->getGalleryManager()->remove($gallery);
        }

    }

    public function testComments() {
        $this->createGallery();
        $this->createComment();
        $this->getComment();
        $this->updateComment();
        $this->deleteComment();
        $this->getComments();
        $this->getGalleries();
        $this->removeGallery();
    }

}

Код включает базовый класс тестирования (BaseUserTest.php), который может быть расширен, чтобы легко войти в систему пользователей.

Я также включил пример использования базового класса в пример теста (RestControllerTest.php). Обратите внимание на этот блок кода в RestControllerTest.php:

$client = static::createClient();
$client->getCookieJar()->set($this->cookie);

Идея BaseUserTest заключается в том, что он может создать свой собственный сеанс, заполнить сеанс пользователем, а затем сохранить сеанс в файловой системе, используя MockFileSessionStorage.

Затем сами тесты должны установить cookie на клиенте.

2 голосов
/ 09 декабря 2012

Я знаю, что уже слишком поздно .. Но в случае, если кому-то это нужно, мне удалось зарегистрировать пользователя в моем модульном тесте следующим образом:

1- Сначала определите класс, который даст вам доступ к услугам:

<?php
namespace Tests;

class ContainerAwareUnitTestCase extends \PHPUnit_Framework_TestCase
{
    protected static $kernel;
    protected static $container;

    public static function setUpBeforeClass()
    {
        self::$kernel = new \AppKernel('dev', true);
        self::$kernel->boot();

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

    public function get($serviceId)
    {
        return self::$kernel->getContainer()->get($serviceId);
    }
}

2- Затем объявите тест следующим образом:

<?php

namespace Tests\Menu;

use Tests\ContainerAwareUnitTestCase;
use UserBundle\Entity\User;
use FOS\UserBundle\Security\UserProvider;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\Security\Core\SecurityContext;
use Symfony\Component\HttpFoundation\Request;
use Menu\MenuBuilder;

class MenuBuilderTest extends ContainerAwareUnitTestCase
{
    public function provider()
    {
        return array(array('/'));

    }

    /**
     * @dataProvider provider
     */
    public function testNoAuth($uri) 
    {
        /* @var $securityContext SecurityContext */
        $securityContext = $this->get('security.context');
        $userProvider = $this->get('fos_user.user_provider.username');
        $user = $userProvider->loadUserByUsername('alex');
        $token = new UsernamePasswordToken($user, null, 'main', array('ROLE_USER'));
        $securityContext->setToken($token);

        /* @var $menuBuilder MenuBuilder */
        $menuBuilder = $this->get('event_flow_analyser.menu_builder');

        $this->assertNotNull($menuBuilder);

        $request = new Request();
        $request->attributes->set('projectName', 'ucs');

        $menu = $menuBuilder->createMainMenu($request);

        $this->assertNotNull($menu);

        $this->assertNotNull($menu->getChild('Home'));
        $this->assertNotNull($menu->getChild('Profile'));

        $this->assertEquals(null, $menu->getChild('Projects'));
    }

}    

Это полный пример для тестирования создания menuBuilder, но хотя это и немного выходит за рамки, этот фрагмент должен отвечать вашемунужно:

        $securityContext = $this->get('security.context');
        $userProvider = $this->get('fos_user.user_provider.username');
        $user = $userProvider->loadUserByUsername('alex');
        $token = new UsernamePasswordToken($user, null, 'main', array('ROLE_USER'));
        $securityContext->setToken($token);
0 голосов
/ 04 июня 2014

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

0 голосов
/ 29 июля 2012

Вот как я реализовал это для одного из проектов (не с FOSUserBundle, но, вероятно, вы найдете это полезным)

private function createAuthorizedClient($role)
{
    $userProvider = new YourUserProvider(...);
    $user = $userProvider->createUserMethod(...);

    $client = $this->createClient(); //Normal WebTestCase client
    $client->getCookieJar()->set(new Cookie(session_name(), true));
    $session = self::$kernel->getContainer()->get('session');
    $token =  new UsernamePasswordToken($user, 'password', 'main', array($role));
    $client->getContainer()->get('security.context')->setToken($token);
    $session->set('_security_main', serialize($token));

    return $client;
}

Не забудьте смоделировать ожидаемые результаты для объекта пользователя.

...