3

我正在使用带有 FOSUserBundle 的 Symfony,现在我想测试一些东西,例如:

  • 教义生命周期
  • 防火墙后的控制器

对于这些测试,我需要成为特定用户或至少在用户组中。我如何模拟用户会话,以便...

  • 像“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.
    }
}
4

3 回答 3

2

您可以使用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('foo@bar.com')
            ->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);
}
于 2016-03-06T15:22:39.023 回答
2

在这种情况下,我要做的是创建一个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_idsession.storage.mock_fileconfig_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官方文档中看到一个示例。

于 2016-03-06T08:38:33.293 回答
1

您可以使用 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]'] = 'testfgdf@grgreger.fr';
$form['fos_user_profile_form[current_password]'] = 'gfgfgdgpk5dfgddf';

像这样在存储库用户中调用 findOneBy 来测试“createdAt”

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

$this->assertTrue($user->getCreatedAt() == now());
于 2016-02-22T22:47:27.113 回答