12

Symfony2 / Doctrine2 で Behat を使用しています。ここで、「ログインして /login に移動する場合は、代わりに / に移動する必要がある」という事実に要約されるこのシナリオがあります。

@login
Scenario: Go to the login page while being logged in
  Given I am logged in
  When I go to "/login"
  Then I should be on "/"

@login については、次のものを作成しました。

/**
 * @BeforeScenario @login
 */
public function loginUser()
{
    $doctrine = $this->getContainer()->get('doctrine');
    $userRepository = $doctrine->getRepository('MyTestBundle:User');
    $user = $userRepository->find(1); // 1 = id

    $token = new UsernamePasswordToken($user, NULL, 'main', $user->getRoles());
    $this->getContainer()->get('security.context')->setToken($token);
}

「/login に移動するとき」コード (コントローラーが呼び出される) では、トークンがなくなったように見えます (意図したものではありません)。

/**
 * @Route("/login", name="login")
 */
public function loginAction()
{
    $token = $this->get('security.context')->getToken();
    $fd = fopen('/tmp/debug.log', 'a');
    fwrite($fd, $token);

    // prints 'AnonymousToken(user="anon.", authenticated=true, roles="")'
    ...

しかし、FeatureContext では、それは固執しているようです (私が望んでいた方法で動作します)。「ログインしている場合」で:

/**
 * @Given /^I am logged in$/
 */
public function iAmLoggedIn()
{        
    $token = $this->getContainer()->get('security.context')->getToken();
    $fd = fopen('/tmp/debug.log', 'a');
    fwrite($fd, $token);

    // prints 'UsernamePasswordToken(user="admin", authenticated=true, roles="ROLE_ADMIN")'
    ...

私は次のように実行します:

app/console -e=test behat

テストであることを確認するために、コントローラーでもこれを行いました。

fwrite($fd, $this->get('kernel')->getEnvironment());
// prints 'test'

ユーザーを認証する方法の手がかりはありますか? 多くの管理ページをテストする必要があるため、ブロックされないように、ログインを @BeforeSuite、@BeforeFeature (または @BeforeScenario ...) にフックできればいいと思います。

(テストのために認証メカニズムを無効にすることに関する提案、またはユーザーをスタブ/モックする方法も歓迎します。)

4

4 に答える 4

20

なんてこった。FeatureContext 内の DIC がアプリと共有されていないため、機能しません。アプリには個別のカーネルと DIC があります。ミンクから入手できます。または、単に正しい方法で行うこともできます:-)

正しい方法は、エンドユーザーが観察できる動作のすべての部分を、FeatureContext 内ではなく *.feature 内に記述する必要があることを意味します。つまり、ユーザーをログインさせたい場合は、単純に手順を説明する必要があります (「私は /login にいます」、「ユーザー名を入力します...」、「パスワードを入力します」など)。 . 複数回実行する場合は、メタステップを作成する必要があります。

メタステップは、他の複数のステップを説明する単純なステップです。たとえば、「私は everzet としてログインしています」などです。ここでそれらを読むことができます:http://docs.behat.org/guides/2.definitions.html#step-execution-chaining

于 2011-11-12T22:44:17.663 に答える
1

これは、私が使用したOAuthでログインするためのソリューションです。何度も答えを探してこのページにたどり着いた後、解決策を共有するのは素晴らしいことだと思いました. うまくいけば、それは誰かを助けるでしょう。

背景: HWIOAuthBundle を使用する Symfony2 アプリは、いくつかの OAuth2 プロバイダーに接続されています。

問題Given I'm logged in: Behat コンテキストが Symfony コンテキストと共有されていない場合、どのように実装すればよいですか?

解決策:

HWIOAuthBundle は@buzz、OAuth プロバイダーへのすべての API 呼び出しにサービスを使用します。したがって、Buzz クライアントを、外部サービスを呼び出さずにすぐに結果を返す実装に置き換えるだけで済みます。これは私の実装です:

<?php

namespace Acme\ExampleBundle\Mocks;

use Buzz\Client\ClientInterface;
use Buzz\Message\MessageInterface;
use Buzz\Message\RequestInterface;

class HttpClientMock implements ClientInterface
{
    public function setVerifyPeer()
    {
        return $this;
    }

    public function setTimeout()
    {
        return $this;
    }

    public function setMaxRedirects()
    {
        return $this;
    }

    public function setIgnoreErrors()
    {
        return $this;
    }

    public function send(RequestInterface $request, MessageInterface $response)
    {
        if(preg_match('/\/oauth2\/token/', $request->getResource()))
        {
            $response->setContent(json_encode([
                'access_token' => 'valid',
                'token_type' => 'bearer',
                'expires_in' => 3600
            ]));
        }
        elseif(preg_match('/\/oauth2\/me/', $request->getResource()))
        {
            $response->setContent(json_encode([
                'id' => 1,
                'username' => 'doctor',
                'realname' => 'Doctor Who'
            ]));
        }
        else throw new \Exception('This Mock object doesn\'t support this resource');
    }
}

次のステップは、HWIOAuthBundle/Buzz で使用されるクラスを乗っ取り、上記の実装に置き換えることです。テスト環境でのみ行う必要があります。

# app/config/config_test.yml
imports:
    - { resource: config_dev.yml }

parameters:
    buzz.client.class: Acme\ExampleBundle\Mocks\HttpClientMock

最後に、テスト環境では false に設定する必要があるためrequire_previous_session、パラメーターとして渡すことをお勧めします。

# app/config/security.yml
security:
    firewalls:
        secured_area:
            oauth:
                require_previous_session: false

これで、このようにステップを実装できます。

仕様:

Feature: Access restricted resource

  Scenario: Access restricted resource
    Given I'm logged in
    When I go to "/secured-area"
    Then I should be on "/secured-area"
    And the response status code should be 200

実装:

<?php
/**
 * @Given /^I\'m logged in$/
 */
public function iMLoggedIn()
{
    $this->getSession()->visit($this->locatePath('/login/check-yourOauthProvider?code=validCode'));
}

渡すコードは関係ありません。渡したものはチェックされていないため、問題ありません。HttpClientMock::sendメソッドでこの動作をカスタマイズできます。

于 2013-10-03T16:30:02.003 に答える
1

http://robinvdvleuten.nl/blog/handle-authenticated-users-in-behat-mink/は、ログイン セッションを作成し、Mink セッション Cookie を設定して、Mink セッションがログインされるようにする方法に関するシンプルでクリーンな記事です。毎回ログイン フォームを使用してユーザーをログインさせるよりもはるかに優れています。

于 2014-12-08T08:29:52.197 に答える