Behat, Symfony 2和FOS用户:如何创建登录测试


Behat, Symfony 2 and FOS User: how to create a login test

我是新来的Behat,我想创建一个功能来验证登录表单。我正在使用FOS用户包。

最简单的方法是:

When I am on "/login"
And I fill in "username" with "admin"
And I fill in "password" with "1234"
And I press "_submit"
Then I should be on "/dashboard"

期望数据库中存在密码为1234的用户"admin"。但我很确定一定有一种方法可以模拟数据库或为FOS创建一个假用户。我一直在谷歌,但找不到任何具体的。

理想情况下应该是

Given there's a user "admin" with password "1234"
[rest of the test]

任何想法?谢谢!

您可以定义一个特定的登录步骤,并在不同的测试中重用它。您甚至不需要密码,通过令牌模拟身份验证。

例如:

/**
 * @Given /^I am authenticated as "([^"]*)"$/
 */
public function iAmAuthenticatedAs($username)
{
    $driver = $this->getSession()->getDriver();
    if (!$driver instanceof BrowserKitDriver) {
        throw new UnsupportedDriverActionException('This step is only supported by the BrowserKitDriver');
    }
    $client = $driver->getClient();
    $client->getCookieJar()->set(new Cookie(session_name(), true));
    $session = $client->getContainer()->get('session');
    $user = $this->kernel->getContainer()->get('fos_user.user_manager')->findUserByUsername($username);
    $providerKey = $this->kernel->getContainer()->getParameter('fos_user.firewall_name');
    $token = new UsernamePasswordToken($user, null, $providerKey, $user->getRoles());
    $session->set('_security_'.$providerKey, serialize($token));
    $session->save();
    $cookie = new Cookie($session->getName(), $session->getId());
    $client->getCookieJar()->set($cookie);
}

然后用

命名这个新步骤
Scenario: Displaying the blog overview
Given I am authenticated as "bar"
  And I am on "/admin/"
 Then I should see "Admin dashboard"

有用内容:

  • 此代码的源代码
  • 关于自定义步骤的行为文档

要验证FOSUserBundle登录表单,您可以像这样编写您的特性

Feature: Admin authentication
  In order to gain access to my admin management area
  As an admin
  I need to be able to login
  Scenario: Logging in
    Given there is an admin user "admin" with password "1234"
    And I am on "/login"
    When I fill in "Username" with "admin"
    And I fill in "Password" with "1234"
    And I press "Log in"
    Then I should see "Connected" //or anything that proves you're connected
然后你可以在FeatureContext.php中创建步进验证,如下所示:
/**
 * @Given there is an admin user :username with password :password
 */
public function thereIsAnAdminUserWithPassword($username, $password)
{   // Create an Admin User
    $user = new 'AppBundle'Entity'User();// inherits form FOSUserBundle'Entity'User()
    $user->setUsername($username);
    $user->setPlainPassword($password);
    $user->setEmail("example@mail.com");// required by FOSUserBundle
    $user->setEnabled(true); // add it manually otherwise you'll get "Account is disabled" error
    $user->setRoles(array('ROLE_ADMIN'));
    // Then you must store it in your database
}

问题是FeatureContext.php不能访问容器和实体管理器,如果你不显式声明它,就不能将你的用户存储在数据库中。最简单的方法是使用behat/symfony2扩展,然后只有您能够使用实体管理器并存储管理员用户。如果你正在使用Composer,那么你可以:

composer require --dev behat/symfony2-extension

那么你必须在你的行为中激活扩展。像这样:

default:
# ...
    extensions:
        Behat'Symfony2Extension: ~

只有这样你才能让你的FeatureContext.php意识到容器,这样它才能访问实体管理器。把它添加到你的FeatureContext类中,像这样:

class FeatureContext extends RawMinkContext implements Context, SnippetAcceptingContext
    {
        use 'Behat'Symfony2Extension'Context'KernelDictionary;
    ...
    }

现在您可以调用实体管理器并存储您的admin用户:

/**
 * @Given there is an admin user :username with password :password
 */
public function thereIsAnAdminUserWithPassword($username, $password)
{   // Create an Admin User
    $user = new 'AppBundle'Entity'User();
    $user->setUsername($username);
    $user->setPlainPassword($password);
    $user->setEmail("example@mail.com");
    $user->setRoles(array('ROLE_ADMIN'));
    $user->setEnabled(true); 
    // Store it in the database
    $em = $this->getContainer()->get('doctrine')->getManager();
    $em->persist($user);
    $em->flush();
}

现在您可以使用您的测试!不要忘记在启动测试之前清理数据库,否则在第二次尝试时,您会得到一个很好的错误,说这个用户已经存在!最好的方法是添加一个clearData()函数,在每个场景之前启动,如下所示:

/**
 * @BeforeScenario
 */
public function clearData()
{
    $em = $this->getContainer()->get('doctrine')->getManager();
    $em->createQuery('DELETE FROM AppBundle:User')->execute();
}