8
4

More than 3 years have passed since last update.

Laravel: Cookiesが含んでいるテスト

Last updated at Posted at 2020-01-10

背景

LaravelのCookieの処理

Laravelでは、ユーザーの安全を守るため、MiddlewareでCookieの情報を暗号化され、認証コードで署名しています。CookieがLaravelのフレームワークで暗号化されていない場合(例えばクライエントで弄ったCookieや暗号化されていないCookie)、そのCookieが無効になって、リクエストから削除されます。

PHPUnitでテスト行うとき

LaravelCookieの暗号化処理はすごく良い機能と思いますが、残念ながらテストでリクエスト関数のcallpostなどにCookieを渡せばこの暗号化の処理は自動的に行われていません。

つまり、下記のようにテストでCookieをリクエストに追加して、

HogeControllerTest.php
       public function testHoge()
       {
            $cookie = ['hoge_test' => 'sugehoge'];
            $resp = $this->call(
                'get',
                '/hoge',
                [],
                $cookie
            );
        }

それで下記のようにコントローラーでCookieの値を取得しようとするとnullが出力されてしまします。

HogeController.php
    public function testCookie(Request $request)
    {
        dd(Cookie::get('hoge_test'));
        // null
    }

Cookieを含んでいるテストする方法

Laravel 6.x 以上

このPR で簡単にCookieの処理ができるように関数を追加がしました。

withCookies()

テストでリクエストを呼ぶときwithCookies($array)関数を追加して、['キー' => '値']の配列を引数としてわたすだけで、Cookieの暗号化の処理が行われます。

注意点

PRによると

To remain backwards compatible, the call method does not honor cookies set by these new methods.

後方互換のためこの新しい追加した機能はcall()関数対応ではありません!つまりこの機能使いたいときリクエストの種類の名前のpost()get()などの関数を使う必要があります。

HogeControllerTest.php
   public function testHoge()
   {
        $cookie = ['hoge_test' => 'sugehoge'];
        // withCookiesの関数追加
        // call()ではなく、get()にする
        $resp = $this->withCookies($cookie) 
            ->get('/hoge', []);
   }

テスト実行すれば、sugehogeがちゃんと出力されます。

ちなみに、Cookieを一つだけ設定するwithCookie($name, $value)の関数も用いて、Cookieのキーを引数としてわたせば、withCookies($array)と同じようにCookieが正しく設定されます。

すごく便利な機能ですね!

Laravel 5.x 以上

勿論、下記に書いてある項目の方法はLaravel 6.x でも使う可能で、それがこのみなら使っても構いません!

Middlewareを無効にする

Cookieの暗号化はEncryptCookiesのミドルウエアで行われているので、それを無効すれば、テストが無事に走るはず。Laravelのテストではミドルウエアを無効にするWithoutMiddlewareのトレイトが用いていて、それが使えます。

HogeControllerTest.php
   use WithoutMiddleware;

   public function testHoge()
   {
        // middlewareを無効
        $this->withoutMiddleware(EncryptCookies::class);
        $cookie = ['hoge_test' => 'sugehoge'];
        // post()じゃなくて、call()つかいます
        $resp = $this->call('get', '/hoge', [], $cookie);
    }

今回テストをはしると,sugehoge、がちゃんと出力されます!

Cookieを暗号化する

テストで暗号化が行われていないので、Cookieの値を暗号化するとテストが走るはず。Laravelのヘルパー関数encrypt()で暗号化処理ができる。

HogeControllerTest.php
   public function testHoge()
   {
        // Cookieの値の暗号化行う
        $cookie = ['hoge_test' => encrypt('sugehoge', false)];
        $resp = $this->call('get', '/hoge', [], $cookie);
    }

テストをはしると,sugehogeが出力されます。

注意点

encrypt('値', false)の関数にfalseを渡さないと値がserializeされ、"s:12:"sugehoge";"が出力されてしまいます。なので、falseを渡すのを忘れないで下さい。

終わり

いくつかの方法があります。
これから自分のテストにつかってみてください!

参照のリンク

https://readouble.com/laravel/6.x/ja/requests.html#cookies
https://readouble.com/laravel/5.1/ja/testing.html#disabling-middleware
https://github.com/laravel/framework/pull/30101
https://laravel.com/api/6.x/Illuminate/Contracts/Encryption/Encrypter.html
https://github.com/laravel/framework/issues/12032

8
4
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
4