背景
LaravelのCookieの処理
Laravelでは、ユーザーの安全を守るため、Middleware
でCookieの情報を暗号化され、認証コードで署名しています。CookieがLaravelのフレームワークで暗号化されていない場合(例えばクライエントで弄ったCookieや暗号化されていないCookie)、そのCookieが無効になって、リクエストから削除されます。
PHPUnitでテスト行うとき
LaravelCookieの暗号化処理はすごく良い機能と思いますが、残念ながらテストでリクエスト関数のcall
やpost
などにCookieを渡せばこの暗号化の処理は自動的に行われていません。
つまり、下記のようにテストでCookieをリクエストに追加して、
public function testHoge()
{
$cookie = ['hoge_test' => 'sugehoge'];
$resp = $this->call(
'get',
'/hoge',
[],
$cookie
);
}
それで下記のようにコントローラーでCookieの値を取得しようとするとnull
が出力されてしまします。
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()
などの関数を使う必要があります。
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
のトレイトが用いていて、それが使えます。
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()
で暗号化処理ができる。
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