概要
調べ方が悪いのかもしれないけど、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 に登録していない id
や created_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));
}
}