0
0

Laravel API Resourceのテスト

Last updated at Posted at 2024-02-06

概要

調べ方が悪いのかもしれないけど、APIResourceのテストを書いた記事が見つけられなかった。
Featureテストを使えばリクエストからレスポンスまでをテスト出来るので、あまり需要はないかもしれないけど備忘録として残しておく。

環境

  • Laravel10
  • PHP8.1
  • MySQL8

Resource に Model を渡すケース

ControllerからユーザーモデルをResourceクラスに渡す

UserShowController.php
<?php

declare(strict_types=1);

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Http\Resources\UserShowResponseResource;

final class UserShowController extends Controller
{
    /**
     * @param int $userId
     *
     * @return UserShowResponseResource
     */
    public function __invoke(int $userId): UserShowResponseResource
    {
        // ユーザーを取得
        $user = User::where('id', $userId)->first();

        return new UserShowResponseResource($user);
    }
}

Resourceの実装はこんな感じ

UserShowResponseResource.php
<?php

declare(strict_types=1);

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class UserShowResponseResource extends JsonResource
{
    /**
     * Transform the resource into an array.
     *
     * @param \Illuminate\Http\Request $request
     *
     * @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
     */
    public function toArray($request): array
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'email' => $this->email,
            'created_at' => $this->created_at->toDateTimeString(),
            'updated_at' => $this->updated_at->toDateTimeString()
        ];
    }
}

実際のテストはこちら

UserShowResponseResource.php
<?php

declare(strict_types=1);

namespace Tests\Unit\Http\Resources;

use App\Http\Resources\UserShowResponseResource;
use App\Models\User;
use Illuminate\Http\Request;
use Tests\TestCase;

class UserShowResponseResourceTest extends TestCase
{
    /**
     * @test
     */
    public function ユーザー詳細のレスポンスを取得できる()
    {
        $user = new User();
        $user->id = 1;
        $user->name = '田中 太郎';
        $user->email = 'user@example.com';
        $user->created_at = '2024-01-01 00:00:00';
        $user->updated_at = '2024-01-01 00:00:00';

        $expected = [
            'id' => 1,
            'name' => '田中 太郎',
            'email' => 'user@example.com',
            'created_at' => '2024-01-01 00:00:00',
            'updated_at' => '2024-01-01 00:00:00'
        ];

        $this->assertEquals($expected, (new UserShowResponseResource($user))->toArray(Request::class));
    }
}

注意
例ではプロパティを代入していますが、以下のようにモデルに値を渡すようにすると $fillable に登録していない idcreated_at updated_at の返り値がnullになってしまうので気をつけましょう。

        $user = new User([
            'id' => 1,
            'name' => '田中 太郎',
            'email' => 'user@example.com',
            'created_at' => '2024-01-01 00:00:00',
            'updated_at' => '2024-01-01 00:00:00'
        ]);

Resource に Collection を渡すケース

ControllerからユーザーモデルをResourceクラスに渡す

UserListController.php
<?php

declare(strict_types=1);

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Http\Resources\UserListResponseResource;

final class UserListController extends Controller
{
    /**
     * @return UserListResponseResource
     */
    public function __invoke(): UserListResponseResource
    {
        // ユーザー一覧を取得
        $users = User::get();

        return new UserListResponseResource($users);
    }
}

Resourceの実装はこんな感じ

UserListResponseResource.php
<?php

declare(strict_types=1);

namespace App\Http\Resources;

use App\Models\User;
use Illuminate\Http\Resources\Json\ResourceCollection;

class UserListResponseResource extends ResourceCollection
{
    /**
     * Transform the resource into an array.
     *
     * @param \Illuminate\Http\Request $request
     *
     * @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
     */
    public function toArray($request): array
    {
        return $this->resource->map(fn (User $user) => [
            'id' => $user->id,
            'name' => $user->name,
            'email' => $user->email,
            'created_at' => $user->created_at->toDateTimeString(),
            'updated_at' => $user->updated_at->toDateTimeString()
        ])->all();
    }
}

実際のテストはこちら

UserListResponseResource.php
<?php

declare(strict_types=1);

namespace Tests\Unit\Http\Resources;

use App\Http\Resources\UserListResponseResource;
use App\Models\User;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Http\Request;
use Tests\TestCase;

class UserListResponseResourceTest extends TestCase
{
    /**
     * @test
     */
    public function ユーザー一覧のレスポンスを取得できる()
    {
        $user = new User();
        $user->id = 1;
        $user->name = '田中 太郎';
        $user->name_kana = 'たなか たろう';
        $user->email = 'user@example.com';

        $users = new Collection([$user]);

        $expected = [
            [
                'id' => 1,
                'name' => '田中 太郎',
                'name_kana' => 'たなか たろう',
                'email' => 'user@example.com'
            ],
        ];

        $this->assertEquals($expected, (new UserListResponseResource($users))->toArray(Request::class));
    }
}

Model に Collection が紐づいているケース

Controllerから投稿が紐づいたユーザーモデルをResourceクラスに渡す

UserShowController.php
<?php

declare(strict_types=1);

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Http\Resources\UserShowResponseResource;

final class UserShowController extends Controller
{
    /**
     * @param int $userId
     *
     * @return UserShowResponseResource
     */
    public function __invoke(int $userId): UserShowResponseResource
    {
        // ユーザーを取得
        $user = User::where('id', $userId)->with('posts')->first();

        return new UserShowResponseResource($user);
    }
}

Resourceの実装はこんな感じ

UserShowResponseResource.php
<?php

declare(strict_types=1);

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;
use App\Models\Post;

class UserShowResponseResource extends JsonResource
{
    /**
     * Transform the resource into an array.
     *
     * @param \Illuminate\Http\Request $request
     *
     * @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
     */
    public function toArray($request): array
    {
        return [
            'id' => $this->id,
            'posts' => $this->resource->map(fn (Post $post) => ['title' => $post->title])->all();
            'name' => $this->name,
            'email' => $this->email,
            'created_at' => $this->created_at->toDateTimeString(),
            'updated_at' => $this->updated_at->toDateTimeString()
        ];
    }
}

実際のテストはこちら

UserShowResponseResource.php
<?php

declare(strict_types=1);

namespace Tests\Unit\Http\Resources;

use App\Http\Resources\UserShowResponseResource;
use App\Models\Post;
use App\Models\User;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Http\Request;
use Tests\TestCase;

class UserShowResponseResourceTest extends TestCase
{
    /**
     * @test
     */
    public function ユーザー詳細のレスポンスを取得できる()
    {
        $post = new Post();
        $post->title = '本タイトル';
        
        $user = new User();
        $user->id = 1;
        $user->posts = new Collection([$post]);
        $user->name = '田中 太郎';
        $user->email = 'user@example.com';
        $user->created_at = '2024-01-01 00:00:00';
        $user->updated_at = '2024-01-01 00:00:00';

        $expected = [
            'id' => 1,
            'posts' => [['title' => '本タイトル']],
            'name' => '田中 太郎',
            'email' => 'user@example.com',
            'created_at' => '2024-01-01 00:00:00',
            'updated_at' => '2024-01-01 00:00:00'
        ];

        $this->assertEquals($expected, (new UserShowResponseResource($user))->toArray(Request::class));
    }
}
0
0
0

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
0
0