2014-07-17 34 views
0

我正在处理的项目在登录后面有一个api。我如何使用Behat和Mink和WebApiContext?

我使用贝哈特水貂登录:

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想法来自this issue没有成功。当我打印的回应,我刚才看到的HTML页面从登录屏幕..

没有人有任何想法,如果我要完全错误的方式,或者我有点朝着正确的方向?

回答

2

我成功地使用了相同的方法。我不认为有这样做的标准方式。就您了解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(); 
} 

上述步骤定义(贝哈特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; 
} 

我遇到的最大问题是会话重新加载。这可能是由于我的选择框架,我怀疑。第一个代码片段有session_commit(),它保存并关闭会话。从理论上讲,在下面的步骤定义中,您必须能够使用session_id(/* session id from the cookie… */);session_start();,但实际上这并不起作用,并且没有从该文件实际加载会话数据,但会话确实开始。为了解决这个问题,我用reload()方法使用session save handler创建了一个自定义会话管理器。

第二个问题是您不能简单地关闭会话,而无需编写或销毁会话(支持在PHP 5.6中添加),因为它依赖于重新加载。我用会议管理器的一个标记重新改变了方向盘,告诉它是写还是仅仅关闭它。

:)

+1

不能希望有更好的答案!非常感谢! –

相关问题