문제

I’m trying to create some tests for a Laravel application using Behat. Many of the tests require that a logged-in user sees specific data. My approach was this:

  • Log in as a user with a particular ID with Auth::loginUsingId($id)
  • Go to a particular URL in my app
  • Check that the content I’m expecting is there

Now, in my Behat context, although Auth::check() returns true, the filter I have set up doesn’t seem to see this. Auth::check() in that context returns false, and thus attempts to authenticate (via OAuth to the API my app talks to).

How can I go about testing my app as a logged-in user?

My Behat context file, in case it’s of help:

<?php

use Behat\Behat\Context\ClosuredContextInterface;
use Behat\Behat\Context\TranslatedContextInterface;
use Behat\Behat\Context\BehatContext;
use Behat\Behat\Exception\PendingException;
use Behat\Gherkin\Node\PyStringNode;
use Behat\Gherkin\Node\TableNode;
use Behat\MinkExtension\Context\MinkContext;

/**
 * Features context.
 */
class FeatureContext extends MinkContext
{
    /**
     * Laravel application instance.
     *
     * @var Illuminate\Foundation\Application
     */
    protected $app;

    /**
     * @static
     * @beforeSuite
     */
    public static function bootstrapLaravel()
    {
        $unitTesting = true;
        $testEnvironment = true;

        $app = require_once __DIR__ . '/../../../../bootstrap/start.php';
        $app->boot();
    }

    /**
     * Initializes context.
     * Every scenario gets its own context object.
     *
     * @param array $parameters context parameters (set them up through behat.yml)
     */
    public function __construct(array $parameters)
    {
    }

    /**
     * @Given /^I am logged in as user ID (\d+)$/
     */
    public function iAmLoggedInAsUserId($id)
    {
        Auth::loginUsingId($id);
    }
}

And a sample test feature:

Feature: Sample Feature

  Scenario: View groups a member is associated with
    Given I am logged in as user ID 49
    And I am on "/group"
    Then I should see "Lorem Ipsum"
도움이 되었습니까?

해결책

The problem you have is that the iAmLoggedInAsUserId method performs calls on the laravel framework directly, where as your subsequent instructions are browser/mink based. This is like having a PHP script which you run from the command line which sets (for its execution) the logged in user to 123, and then going to a web browser - user 123 wouldn't be logged in in that context.

You need to find a way for the code-based authentication to persist to your browser test.

Possible options:

  • An aggregate instruction for iAmLoggedInAsUserId which goes to the login page, and performs the login.
  • Hijack the session being used by mink, and update it to be logged in
  • A local-only work around which lets you, say, set a header to contain a user ID, and your code, only when running locally, uses this as the logged in user

Ideally, you should write a test to test logging in, however that is structured (i.e. option 1) and then re-use that for your tests which require a logged in user. The other two options are simply ideas if you use-case doesn't permit the first.

Edit: The following is an example aggregate instruction, this particular version requires the user exist in the system. You could however force a user to exist before hand, and if it was added as part of the test, delete it once the test is completed using the @AfterFeature hook:

/**
 * @Given /I am logged in with the username "([^"]*)" and password "([^"]*)"/
 */
public function loginWithEmailAndPassword($username, $password)
{
    //$this->ensureUserExistsWithEmailAndPassword($email, $password);

    return array(
        new Behat\Behat\Context\Step\Given("I am on \"/login\""),
        new Behat\Behat\Context\Step\When("I fill in \"login_username\" with \"$username\""),
        new Behat\Behat\Context\Step\When("I fill in \"login_password\" with \"$password\""),
        new Behat\Behat\Context\Step\When("I press \"Login\""),
        new Behat\Behat\Context\Step\Then("I should see \"Welcome\"")
    );
}

다른 팁

Behat is a separate process to the browser session that it is spawning, so logging in like that won't work.

What I normally do is describe the steps for logging in as a test user. Something like the following.

Given I am on the login page
And I fill in "username" with "testuser"
And I fill in "password" with "testpassword"
And I press "Log in"
Then I should be logged in as "testuser"

You can set that up as a background in behat that will run before each scenario.

I'd probably also reduce the steps down to a method in your FeatureContext that can be called in a single step, something like Given I am logged in as "testuser".

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top