引き続きLaravel v8 を使っています。化石を使っています。
前回の続きです。
今回紹介するユースケースとしては、
テストしたいCookie処理を含むサービス存在しており、そのメソッド使用しているcontrollerのURLを呼ぶと色々副作用がありそうで面倒くさそうなので、そのメソッド単体を呼び出せるようにしてテストしたい
というケースです。
Cookie関連の処理を含むメソッドは、Cookieの特性上、URLリクエストを通してテストする必要があります。
この方法で取得されるCookieは暗号化されているので、暗号化処理のミドルウェアを無効にします。use で WithoutMiddleware をインポートすると他のミドルウェアも無効になってしまうので、以下の記述を対象のテストケースの先頭に書きます。
$this->WithoutMiddleware(\App\Http\Middleware\EncryptCookies::class);
テストしたいメソッドは以下です。Cookie::queue()
メソッドが含まれている処理です。
public static function refresh_cookie () {
$cookie = Cookie::get("cookie1");
if ($cookie) {
return $cookie;
}
$cookieList = ['A', 'B', 'C'];
$newCookie = $cookieList[array_rand($cookieList)];
Cookie::queue("test", $newCookie, '30');
return $newCookie;
}
次に、対象メソッドを呼び出すテスト用のパスを作っちゃいましょう。
routes/web.php
Route::get('/test-cookie', function () {
$newCookie = ArticleService::refresh_cookie();
$cookie = cookie('cookie1', $newCookie, 60);
return response('Cookie has been set')->cookie($cookie);
});
Cookie::queue()
は、リクエストの終了後にクッキーを設定する非同期関数なので、リクエストを走らせてレスポンスを取得する必要があります。
そのために、テストリクエスト用のパスを作る必要があるということですね。そしてレスポンスにメソッドで取得したクッキーをセットする必要もあります。
こうして環境構築をして、出来上がったテストコードは以下のようになります。
public function test_refresh_cookie__クッキーが設定されているか(): void
{
// Cookieの暗号化を無効にする
$this->WithoutMiddleware(\App\Http\Middleware\EncryptCookies::class);
$cookies = ['cookie1' => null];
$response = $this->call('GET', '/test-aaa', $cookies);
$cookie = $response->headers->getCookies()[0];
$this->assertContains($cookie->getValue(), ["A", "B", "C"]);
# -> OK
}
ところで、公式のCookie偽装方法は、withCookie
, withCookies
を使用してGETリクエストを送信しています。
$response = $this->withCookie('cookie1', 'A')->get('/');
しかしこのメソッドではミドルウェアを無効にしても暗号化がされたものが取得されます。
なので以下をミドルウェアの無効化の記述の下に挿入します。
$this->WithoutMiddleware(\App\Http\Middleware\EncryptCookies::class);
$this->disableCookieEncryption();
この場合の完成系は以下になります。
public function test_refresh_cookie__クッキーが設定されているか(): void
{
// Cookieの暗号化を無効にする
$this->WithoutMiddleware(\App\Http\Middleware\EncryptCookies::class);
$this->disableCookieEncryption();
$cookies = ['cookie1' => null];
$response = $this->withCookies($cookies)->get('/test-cookie');
$cookie = $response->headers->getCookies()[0];
$this->assertContains($cookie->getValue(), ["A", "B", "C"]);
# -> OK
}
Cookieをランダムに返しているため、assertion
は assertContains
を利用していますが、取得できるCookieが自明の場合なら、assertCookie
や assertPlainCookie
でアサーションしましょう。
こうしてCookieの処理を持つ関数を他に影響を及ぼすことなく/考慮することなく、テストが出来ます。