2014-07-17 39 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

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

相關問題