2015-11-10 91 views
6

首先我讀了this related questionthis other approach (blog post)Behat和Symfony2之前登錄場景

這是我behat.yml

default: 
    suites: 
     users: 
      contexts: 
       - DoctrineFixturesContext 
       - FeatureContext 
       - Behat\MinkExtension\Context\MinkContext 
       - Sanpi\Behatch\Context\RestContext 
       - Sanpi\Behatch\Context\JsonContext 
      paths: [%paths.base%/features/users] 
    extensions: 
     Behat\Symfony2Extension: 
      kernel: 
       env: "test" 
       debug: "true" 
     Behat\MinkExtension: 
      base_url: '' 
      sessions: 
       default: 
        symfony2: ~ 
     Sanpi\Behatch\Extension: ~ 

現在我想的是重現用戶,這是該行爲:在一次

  • 要求

    • 用戶登錄有那麼帶標記的Authorization標頭

    我發現的最簡單的方法是簡單地模仿用戶行爲:

    class FeatureContext implements Context, SnippetAcceptingContext 
    { 
        private $request; 
    
        public function __construct(Request $request) 
        { 
         $this->request = $request; 
        } 
    
        /** 
        * @BeforeScenario @Login 
        */ 
        public function login() 
        { 
         $d = $this->request->send('POST', '/login_check', ['_username' => 'test', '_password' => 'test']); 
         $data = json_decode($d->getContent()); 
         $this->request->setHttpHeader('Authorization', 'Bearer '.$data->token); 
        } 
    } 
    

    用戶是通過預先加載夾具。這種運作良好,除了Authorization頭不通過下面的步驟保持:

    Feature: Get my availables menus 
        @Login 
        Scenario: Get my menus 
        When I send a "GET" request to "/api/menus" 
        Then the response status code should be 200 
    

    的響應是401

    爲什麼不通過的情況保持了Authorization頭?我怎樣才能完成這個簡單的任務?

  • 回答

    1

    正如你可以閱讀here,在here之後,Behatch/RestContext是非常有用的(很多快捷方式和少量方法),但是它與symfony2集成相當混亂。

    正如@stof說,在this comment

    其餘上下文完全是一個巨大的錯誤。 Mink不是REST客戶端(瀏覽器也不是REST客戶端)。使用Mink驅動程序執行REST API調用沒有任何意義。這是工作的錯誤工具。

    Longo故事簡介:似乎您設置的請求標頭未與請求一起傳遞。

    說了這麼多,你可以用這個解決方法嘗試:

    Feature: Get my availables menus 
        @Login 
        Scenario: Get my menus 
        # note the change in the following line 
        # When I send a "GET" request to "/api/menus" 
        When I am on "/api/menus" 
        Then the response status code should be 200 
    

    基本上,使用當我在...您正在使用的MinkContext和請求頭正確地與請求中傳遞。

    當然,我知道這不是一個完美的解決方案(例如:如何處理POST請求??),但至少您所描述的具體測試應該通過。

    讓我知道。 Ciao

    +0

    有沒有別的不使用瀏覽器的水貂? Behat的語法很好寫測試,我也可以[另闢蹊徑](https://twitter.com/s0yuka/status/452045934353211392?lang=en)來測試我的api。 – soyuka

    +0

    問題不在貂皮。 「問題」是Behatch擴展(尤其是與請求頭部相關的東西),無論如何,我也使用了很多,因爲它們非常方便。正如我寫的,你仍然可以使用小黃瓜語言(Behat語法)... – dop3

    +0

    我當然明白,我的問題在於,頭文件並非通過場景持久化。從你所說的話來看,盡我所能做到的事情是不可能的,或者我不得不避免POST請求。 我認爲我會使用Gerkin和nodejs編寫我的api測試......減少頭痛。 – soyuka

    1

    爲什麼授權標頭沒有保留在場景中?我怎樣才能完成這個簡單的任務?

    我想首先這是什麼Request對象,你注入你的上下文?如果您的想法是注入將在Symfony應用程序中使用的請求對象,那麼當Mink將「訪問該頁面」時,這不會像對象will be created by the front controller那樣工作。此外,我建議直接在您的上下文文件中使用Symfony的內核來向您的應用程序發送請求。隨着貝哈特的Symfony2Extension,可以實例化FeatureContext與內核時提到要在behat.yml文件注入服務:

    default: 
        suites: 
         users: 
          contexts: 
           - FeatureContext: 
             - @kernel 
    

    然後,您可以手動創建的請求對象,並將它們發送到的Symfony核心。這裏的發送幾乎相同POST要求比你的榜樣的例子:

    class FeatureContext implements Context, SnippetAcceptingContext 
    { 
        private $kernel; 
    
        public function __construct(KernelInterface $kernel) 
        { 
         $this->kernel = $kernel; 
        } 
    
        /** 
        * @What user :username is authenticating itself with :password 
        */ 
        public function userIsAuthenticatingItselfWith($username, $password) 
        { 
         $response = $this->kernel->handle(Request::create(
          '/login_check', 
          'POST', 
          [], 
          [], 
          [], 
          [ 
           'CONTENT_TYPE' => 'application/x-www-form-urlencoded' 
          ], 
          http_build_query([ 
           '_username' => $username, 
           '_password' => $password, 
          ]) 
         )); 
    
         // Do whatever you want with the `$response` object to check that 
         // the user is successfully authenticated for instance.. 
        } 
    } 
    

    但是你可以看到,我改變方法簽名,實際上並沒有存儲令牌或其他任何東西:這是爲了實際測試此認證,但不作爲給定步驟。

    Symfony身份驗證系統包含一個存儲當前身份驗證令牌的對象TokenStorage。所以,如果你想「假」的認證,你可以簡單地設置在對象令牌,用步驟定義,可能會看起來像:

    class SecurityContext implements Context 
    { 
        /** 
        * @var TokenStorageInterface 
        */ 
        private $tokenStorage; 
    
        /** 
        * @param TokenStorageInterface $tokenStorage 
        */ 
        public function __construct(TokenStorageInterface $tokenStorage) 
        { 
         $this->tokenStorage = $tokenStorage; 
        } 
    
        /** 
        * @Given I am authenticated as :username 
        */ 
        public function iAmAuthenticated() 
        { 
         $token = new YourTokenClass(['ROLE_USER']); 
         $token->setUser(new YouUserClass($username)); 
    
         $this->tokenStorage->setToken($token); 
        } 
    } 
    

    然後,而不是場景鉤子,你可以簡單地在您的方案中使用Given I am authenticated as :username,或者甚至使用​​。

    +0

    看起來很有意思!我應該試試這個 –