23

ほとんどのテストの前に、ログインを保持または実行したいと考えています。しかし、ログイン コードを _before に移動しようとすると、利用可能な webguy インスタンスがないため機能しません。

複数のテスト間でセッションを維持する最良の方法は何ですか? これまでのところ、これは私のコードです。助けていただければ幸いです。ドキュメントをググって確認しましたが、セッションに関するものは何も見つかりません。

<?php
use \WebGuy;

class ProductCest
{

    private $product_id = '1';

    public function _before()
    {
    }

    public function _after()
    {
    }

    // tests
    public function login(WebGuy $I) {
        $I->seeInCurrentUrl('/auth/login');
        $I->fillField("//input[@type='email']", "username@email.com");
        $I->fillField("//input[@type='password']", "1234");
        $I->click('#signIn .submit');
        $I->wait(500);

        $I->seeInCurrentUrl('/account');
    }

    /**
     * @depends login
     */
    public function chooseProduct(WebGuy $I) {
        $I->wantTo('go to products and choose one');
        $I->amOnPage('/?product=' . $this->client_id);
    }

}
4

8 に答える 8

22

受け入れられた答えはそれを達成する方法だと思いますが、最善ではありません。ユーザーセッションを共有するだけでよい場合は、システムにログインするためのすべての手順を常に再現する必要があります。セッション Cookie を取得して、必要なユーザー ログ テストに渡す方がよいと思います。そのためには、ログイン関数を作成し、Cookie を取得して、最初にログイン テストに依存するテストを作成します。

<?php
use \AcceptanceTester;

class testingCest
{
    private $cookie = null;

    public function _before(AcceptanceTester $I)
    {
    }

    public function _after(AcceptanceTester $I)
    {
    }


    // tests
    public function login(AcceptanceTester $I)
    {
        $I->wantTo('entrar al sistema');
        $I->amOnPage('/');
        $I->seeInCurrentUrl('/admin/login');
        $I->fillField('user','perry');
        $I->fillField('pass','pass-perry');
        $I->click('Login');
        $I->see('You\'re logged!');
        $this->cookie   = $I->grabCookie('your-session-cookie-name');
    }

    /**
     * @depends login
     */
    public function listUsers(AcceptanceTester $I)
    {
        $I->setCookie( 'your-session-cookie-name', $this->cookie );
        $I->amOnPage('/admin/users');
        $I->seeInCurrentUrl('/admin/users/1');
    }

    /**
     * @depends login
     */
    public function listRols(AcceptanceTester $I)
    {
        $I->setCookie( 'your-session-cookie-name', $this->cookie );
        $I->amOnPage('/admin/rols');
        $I->seeInCurrentUrl('/admin/rols/1');
    }
}

そうすれば、ログイン テストが失敗した場合、Cookie を取得できず、他のテストに合格できなくなります。

他の回答で提案されたものでは@dependsなく、この注釈を好みます。これを使用すると、前にテストで常にコードを実行し、テストはログイン後にのみ実行されるためです。@before@depends

アップデート

Codeception のフレームワークがこの回答の執筆以降に進化したため、 https: //stackoverflow.com/a/41109855/1168804 という別の回答も役立つ可能性があります。

于 2014-08-28T11:03:59.767 に答える
6

以前の回答はすべて古いものでしたが、現在は Actor クラスを引数として取る _before メソッドで直接行われています。

<?php

namespace Test\Api;

use ApiTester;

class TrainingCest
{
    public function _before(ApiTester $I)
    {
        $I->amLoggedInAs('kgkg');
    }

    public function _after(ApiTester $I)
    {
    }

    // tests
    public function testForLoggedInUser(ApiTester $I)
    {
    }

    public function anotherTestForLoggedInUser(ApiTester $I)
    {
    }

}

また、すべての CEST ファイルに対して 1 回だけログインする場合は、レジストリ デザイン パターンを実装するグローバル レジストリ クラスを使用できます ( https://dzone.com/articles/practical-php-patterns/basic/practical-php-patterns-を参照)。 0 ) といくつかの遅延読み込み。Actor クラス (私の場合は ApiTester) で定義された API 統合テストの作業コードを次に示します。

public function amLoggedInAs($userLogin)
{
    $I = $this;

    if (Registry::getInstance()->exists($userLogin)) {
        // get data from registry
        $storedUserData = Registry::getInstance()->get($userLogin);
        $newAccessToken = $storedUserData['accessToken'];
        $playerId = $storedUserData['playerId'];
    }
    else {
        // no registry data - log in and save data in registry
        $I->tryToLogin($userLogin);

        $newAccessToken = $I->grabDataFromResponseByJsonPath('data.newToken');
        $playerId = (int)$I->grabDataFromResponseByJsonPath('data.userId');
        Registry::getInstance()->set($userLogin, [
            'accessToken' => $newAccessToken,
            'playerId' => $playerId
        ]);
    }

    // finally set headers and some other data
    $I->haveHttpHeader('X-Token', $newAccessToken);
    $I->havePlayerId($playerId);
}

protected function tryToLogin($userLogin)
{
    $I = $this;

    $I->wantTo('login into api');
    $I->amGoingTo('try to log to API using login and password');
    $I->sendPOST('/system/login', ['login' => $userLogin, 'password' => self::getPassword($userLogin)]);

    // ...some other checking if user was correctly logged in ...
}

このコードは基本的に、ユーザーが初めてログインした後、いくつかの追加データとともに accessToken をレジストリに保存します。$I->amLoggedInAs('kgkg') への別の呼び出しが呼び出されると、レジストリからこれらの値が取得されます。この方法で多数のユーザーをログに記録できます。各ユーザーはスイートごとに 1 回だけログに記録されます。

カスタム トークンの代わりに別の認証方法を使用できますが、ロジックは同じです。

また、 (PhpBrowser ではなく) WebDriver を使用している場合は、Registry の代わりに loadSessionSnapshot と saveSessionSnapshot を使用して、まったく同じ結果を得ることができます。

于 2016-12-12T21:25:58.553 に答える
1

私の場合、2021年には.ymlファイルでfalseclear_cookiesに設定するのと同じくらい簡単でした..

ベスト プラクティスとして、テスト間でログインしたままにする必要があるため、Codeception はテスト間で Cookie を削除します。

ただし、Cookie を永続化する場合は、次のように宣言するだけです。

actor: AcceptanceTester
modules:
    enabled:
        - WebDriver:
              clear_cookies: false
于 2021-06-04T06:19:59.620 に答える
1

@Sinisaの回答は「機能する」ものですが、「正しい」ものではないと思います。

必要なのは @depends アノテーションではなく、@before です。

違いは、@depends を使用すると現在のコンテキストが保持されず、@before を使用するとコンテキストが保持されることです。

public function foo(WebGuy $I)
{
    $I->amOnPage('/foobar');
}

/**
 * @depends foo
 */
public function bar(WebGuy $I)
{
    $I->seeInCurrentUrl('foobar'); // Wil fail
}

/**
 * @before foo
 */
public function baz(WebGuy $I)
{
    $I->seeInCurrentUrl('foobar'); // Will pass
}
于 2014-06-28T13:43:46.703 に答える