如何将Behat与Mink和WebApiContext一起使用?

如何将Behat与Mink和WebApiContext一起使用?,api,symfony,behat,mink,Api,Symfony,Behat,Mink,我正在处理的项目在登录后有一个api 我正在使用behat with mink登录: Scenario: Login Given I am on "/login/" And I should see "Login" When I fill in "_username" with "test" And I fill in "_password" with "test" And I press "_submit" Then I should be on "/" 这很有效 但

我正在处理的项目在登录后有一个api

我正在使用behat with mink登录:

Scenario: Login
  Given I am on "/login/"
  And I should see "Login"
  When I fill in "_username" with "test"
  And I fill in "_password" with "test"
  And I press "_submit"
  Then I should be on "/"
这很有效

但是,每当我想使用WebApiContext执行以下操作时,都不会存储登录会话:

Scenario: Getting the list of pages
  When I send a GET request to "/api/pages.json"
  Then print response
我在同一功能中使用这两种场景。我的FeatureContext类如下所示:

class FeatureContext extends MinkContext
{
    public function __construct(array $parameters)
    {
        $context = new WebApiContext($parameters['base_url']);
        $context->getBrowser()->getClient()->setCookieJar(new \Buzz\Util\CookieJar());
        $this->useContext('web', $context);
    }
}
我添加了cookiejar的想法,但没有成功。。当我打印响应时,我只看到登录屏幕上的HTML页面


有没有人知道我是完全走错了路,还是方向正确?

我成功地使用了同样的方法。我不认为有一个标准的方法来做这件事。只要您了解cookie的基本知识,就应该能够实现解决方案

在常见场景中,客户端向服务器发送带有某些凭据的身份验证请求,服务器验证该请求,启动经过身份验证的会话,并发送回具有该会话id的cookie。以下所有请求都包含该id,因此服务器可以识别被调用方。可以使用特定的头来代替cookie,也可以使用数据库来代替会话,但原理是相同的,您可以(相对)轻松地用Mink模拟它

/**
 * Start a test session, set the authenticated user and set the client's cookie.
 *
 * @Given /^I am signed in$/
 */
signIn()
{
    session_start();
    $_SESSION['user'] = 'jos';
    $this->getSession()->getDriver()->setCookie(session_name(), session_id());
    session_commit();
}
上面的步骤定义(Behat 3)是它的基础,您可以手动创建经过身份验证的会话并将其id设置为客户端。这也必须是其他示例所说明的

当你开始做更复杂的事情时,PHP的会话可能会有问题,而且这个解决方案有几个大的水下岩石。如果要从两个角度(客户端和服务器)运行断言,通常需要同步会话。这可以通过在所有Mink步骤之前更新cookie并在之后重新加载会话来实现

/**
 * @beforeStep
 * @param BeforeStepScope $scope
 */
public function synchroniseClientSession(BeforeStepScope $scope)
{

    // Setup session id and Xdebug cookies to synchronise / enable both.

    $driver         = $this->getSession()->getDriver();

    // Cookie must be set for a particular domain.

    if ($driver instanceof Selenium2Driver && $driver->getCurrentUrl() === 'data:,') {
        $driver->visit($this->getMinkParameter('base_url'));
    }

    // Also enables the debugging support.

    $driver->setCookie(session_name(), session_id());
    $driver->setCookie('XDEBUG_SESSION', 'PHPSTORM');
}

/**
 * @afterStep
 * @param AfterStepScope $scope
 */
public function synchroniseServerSession(AfterStepScope $scope)
{
    $driver = $this->getSession()->getDriver();

    // Only browser kit driver, only initiated requests, only not repeating requests.

    if (!$driver instanceof BrowserKitDriver) {
        return;
    } elseif (($request = $driver->getClient()->getRequest()) === null) {
        return;
    } elseif ($request === self::$request) {
        return;
    }

    // Your logic for reloading the session.

    self::$request = $request;
}
我遇到的最大问题是会话重新加载。这可能是因为我的选择框架,我对此表示怀疑。第一个代码段有
会话\u commit()
,它保存并关闭会话。理论上,在以下步骤定义中,您必须能够
session_id(/*来自cookie的session id…*/)
会话_start(),但实际上这不起作用,并且没有从文件中实际加载会话数据,尽管会话确实启动了。为了解决这个问题,我使用
reload()
方法创建了一个自定义会话管理器

第二个问题是,如果不编写或销毁会话(支持是在PHP5.6中添加的),就不能简单地关闭会话,而这依赖于重新加载本身。我用会话管理器的标志重新设计了轮子,它告诉它是写还是关闭


:)

真希望得到更好的答案!谢谢你,伙计!