Laravel/JWTを捏造してテストする

LaravelPHPテスト駆動開発

JWT: JSON Web Token

JWTAuthライブラリ

JWT: JSON Web Tokenを捏造してテストする

  • APIの機能テストにおいて、
    「所持しているJWTトークンが認証が通るならtrueを返す」
    といったテストを書きたい場合
  • 「ログイン済だったらtrueを返す」ではない
  • ので、withoutMiddlewareトレイトでjwt:authトレイトをバイパスして\Auth::login($user)するわけにはいかない

テスト

<?php

class FeatureTest extends TestCase
{
    /*
    ...
    */

    /**
     * JWT認証をモックするためにリクエストヘッダを捏造する
     * @see {@link https://stackoverflow.com/questions/30060360/how-to-mock-tymondesigns-jwt-auth-in-laravel-5}
     */
    protected function headers()
    {
        $headers = [];
        $token = JWTAuth::fromUser($this->userDao->find(1));
        JWTAuth::setToken($token);
        $headers['Authorization'] = 'Bearer '.$token;
        return $headers;
    }


    /**
     * @test
     */
    public function api_auth_check_JWTありでPOSTするとauthenticated_is_trueが返る()
    {
        // ----------------------------------------
        // 1. 下準備
        //    JWTトークンヘッダーを捏造する
        // ----------------------------------------
        $headers = $this->headers();
    
        // ----------------------------------------
        // 2. アクション
        // ----------------------------------------
        $response = $this->postJson(
            'api/auth/check',
            [],
            $headers
        );
        
        // ----------------------------------------
        // 3. 検証
        // ----------------------------------------
        $response->assertStatus(Response::HTTP_OK);
        $response->assertExactJson(['authenticated' => true]);
    }
    

アプリケーション

<?php

    /**
     * 所持しているJWTトークンが認証が通るかの確認
     * @param  Request $request
     * @return JsonResponse
     */
    public function check(Request $request): JsonResponse
    {
        try {
            JWTAuth::setRequest($request);    // テストがモックしたHTTPリクエストを明示的にセットする必要がある
            JWTAuth::parseToken()->authenticate();
        } catch (JWTException $e) {
            return response()->json(['authenticated' => false]);
        }
        return response()->json(['authenticated' => true]);
    }
  • JWTAuth::setRequest($request)は必須
  • さもないと、(たぶん)app()->make(Request::class)したものが注入されており、
    Authorizationヘッダーが設定されていないのでテストが通らない