BehatはSymfony2ユーザーを認証します

私はSymfony2/Doctrine2でBehatを使っています。さて、私はこのシナリオを持っています。「ログインしてログインすると/代わりに行く」

@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);
}

"私が行く/ログインする"コード(コントローラが呼び出される)では、トークンは消え去っているように見えます(私が意図したものではありません):

/**
 * @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 ...)にフックして、ブロックされないようにするといいでしょう。

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

12

4 答え

ああ、私。 FeatureContext内のDICがあなたのアプリと共有されていないため、機能しません。アプリには別のカーネルとDICがあります。あなたはミンクを通してそれを得ることができます。または、あなたは単にそれを正しい方法で行うことができます:-)

正しい方法とは、エンドユーザが観測可能な動作のあらゆる部分を、FeatureContext内ではなく*。feature内に記述することを意味します。つまり、ユーザーにログインしたい場合は、「私はログインしています」、「ユーザー名を入力...」、「パスワードを入力してください」、および「stuf」などの手順を記述するだけです。 。複数回実行したい場合は、metastepを作成する必要があります。

Metasteps are simply steps, that describe multiple other steps, for example - "i am logged in as everzet". You could read bout them here: http://docs.behat.org/guides/2.definitions.html#step-execution-chaining

19
追加された
ユーザーが特定の領域にアクセスするためにログインページを使用しなければならないという理由だけで、すべてのテストでもログインフォームを使用する必要はありません。これにより、すべてのテストシナリオがログインフォームに結合されます。多くのアプリケーションでは、「私を覚えている」機能や電子メールリンクのログイン(電子メールの確認、パスワードの忘れなど)もあります。 Behavior Driven Developmentというのはエンドユーザーの行動を意味するものではありません。これは、すべての役割、ユーザー、ビジネスグループなどから期待されるシステムの動作を意味します。
追加された 著者 Andrew,
あなたはアプリのカーネルとDICを手に入れることができると言いますが、それはどうですか?
追加された 著者 K. Norbert,
確かにずっと良い(そしてより単純な)。ちょうど私のプロジェクトに変更をプッシュしました。ありがとう!
追加された 著者 tvlooy,
oAuthで承認について話したら何をすればいいですか?私はちょうどそれが助けていないそのようなケースでは、任意の追加手順をせずにログインとして機能コンテキスト内のユーザーを認証する必要があります
追加された 著者 pilot,

http://robinvdvleuten.nl/blog/handle-authenticated-users-in-behat-mink/ is simple, clean article on how to create a login session and set the Mink session cookie so that the Mink session is logged in. This is much better than using the login form every time to login a user.

1
追加された

ここで私が使用したOAuthでログインするためのソリューションです。このページで回答と着陸を何回も検索した後、私は解決策を分かち合うことが素晴らしいと思った。うまくいけばそれは誰かを助けるでしょう。

Background: Symfony2 App using HWIOAuthBundle, hooked up to some OAuth2 provider.

Problem: How do I implement Given I'm logged in when Behat context in not shared with Symfony context?

Solution:

HWIOAuthBundleは、OAuthプロバイダへのすべてのAPI呼び出しに @buzz サービスを使用します。したがって、外部サービスを呼び出さない実装と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

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

# 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'));
}

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

1
追加された

ここのUIレイヤの「内側」のレイヤーを呼び出すことは大丈夫です(symfonyではモデルと話す)。 また、symfonyのすべてのユーザにとって、テーブル引数を指定したGivenステップを使用して、フィクスチャの代わりにレコードを設定することをお勧めします。このようにして、シナリオをすべて1か所で読み込み、ファイル間を移動することなくシナリオを理解することができます。

ユーザーがいるとします:
  |ユーザー名|パスワード|電子メール|
  | | 123456 | [email protected] |
  |ファーポット| 22 @ 222 | [email protected] |

0
追加された