laravelのassertJsonメソッド

laravelのテストでは、assertJsonメソッドを使ってAPIのレスポンスを検証できるようになっています。

例えば、routes/api.phpに以下のようなエンドポイントを定義したとき

Route::get('/test', function (Request $request) {
    return response()->json([
        'message' => 'ok',
    ]);
});

レスポンスはこのように検証することができます。

class ExampleTest extends TestCase
{
    public function testBasicTest(): void
    {
        $response = $this->get('/api/test');

        $response->assertJson([
            'message' => 'ok',
        ]);
    }
}

テストを実行するとこのように通ります。

PHPUnit 9.5.4 by Sebastian Bergmann and contributors.


Time: 00:00.253, Memory: 30.00 MB

OK (1 test, 1 assertion)

次に、ユーザーがログインしている時だけ追加のプロパティが返るようなエンドポイントを考えます。

Route::get('/test', function (Request $request) {
    $response = ['message' => 'ok'];

    if ($request->user()) {
        $response['logged in'] = true;
    }

    return response()->json($response);
});

テストコードは先ほどと同じです。ユーザーはログインしていないので、logged inプロパティは含まれないはずです。

class ExampleTest extends TestCase
{
    public function testBasicTest(): void
    {
        $response = $this->get('/api/test');

        $response->assertJson([
            'message' => 'ok',
        ]);
    }
}

テストも通ります。何も問題なさそうに見えます。

PHPUnit 9.5.4 by Sebastian Bergmann and contributors.


Time: 00:00.253, Memory: 30.00 MB

OK (1 test, 1 assertion)

では、ここでエンドポイントの定義をこのように変更してみます。ログインしているかに関わらず、logged inプロパティをセットするように変更しました。

Route::get('/test', function (Request $request) {
    $response = ['message' => 'ok'];

//    if ($request->user()) {
        $response['logged in'] = true;
//    }

    return response()->json($response);
});

この状態でテストを走らせるとどうなるでしょうか?

なんと、テストは通ってしまいます。

PHPUnit 9.5.4 by Sebastian Bergmann and contributors.


Time: 00:00.273, Memory: 30.00 MB

OK (1 test, 1 assertion)

何故テストが通ってしまうのか、その答えはassertJsonメソッドのコメントに書いてあります。

Assert that the response is a superset of the given JSON.

直訳すると「レスポンスがJSONのスーパーセットになっているかを表明します」。つまりこのメソッドは、レスポンスが引数の配列を内包していることを確かめるだけで、余分なプロパティが含まれていないことまでは確かめられないのですね。

PHPUnit 9.5.4 by Sebastian Bergmann and contributors.

Failed asserting that two strings are equal.
Expected :'{"message":"ok"}'
Actual   :'{"logged in":true,"message":"ok"}'

ではどうするか、ですがlaravelにはassertExactJsonという素晴らしいメソッドがあります。このメソッドはレスポンスと引数の配列が厳密に一致することを確かめてくれます。

レスポンスに余分なプロパティが含まれていないこと、を検証する場合はこちらのメソッドを使いましょう。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です