LaravelのFeatureテスト(初歩編)

## はじめに

今回はLaravelでAPIのFeatureテストを書く方法についてです。
ユーザーが投稿を作成・更新・削除できるシンプルなブログ機能を例に、テストの実装方法を記載します。

## 1. 準備
今回は以下の様なPostモデルを準備します。

```php
// ...省略
class Post extends Model
{
    use HasFactory, SoftDeletes;

    protected $fillable = [
        'title',
        'content',
    ];
}
```

## 2. コントローラーの実装
例としてデータ作成・更新・削除の簡単なもので実装します。

```php
// ...省略
class PostController extends Controller
{
    public function store(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'title' => 'required|string|max:255',
            'content' => 'required|string',
        ]);

        $post = Post::create($validated);

        return response()->json($post, 201);
    }

    public function update(Request $request, Post $post): JsonResponse
    {
        $validated = $request->validate([
            'title' => 'required|string|max:255',
            'content' => 'required|string',
        ]);

        $post->update($validated);

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

    public function destroy(Post $post): JsonResponse
    {
        $post->delete();

        return response()->json(null, 204);
    }
}
```

## 3. Featureテストの実装

テスト用のファイルを作成します。
```php artisan make:test Api/PostTest```


```php
// tests/Feature/Api/PostTest.php
// ...省略
class PostTest extends TestCase
{
    use RefreshDatabase;

    public function test_can_create_post(): void
    {
        $postData = [
            'title' => 'テスト投稿',
            'content' => 'これはテスト投稿です。',
        ];

        $response = $this->postJson('/api/posts', $postData);

        $response->assertStatus(201)
            ->assertJson([
                'title' => $postData['title'],
                'content' => $postData['content'],
            ]);

        $this->assertDatabaseHas('posts', [
            'title' => $postData['title'],
            'content' => $postData['content'],
        ]);
    }

    public function test_can_update_post(): void
    {
        $post = Post::factory()->create();

        $updateData = [
            'title' => '更新されたタイトル',
            'content' => '更新された内容',
        ];

        $response = $this->putJson("/api/posts/{$post->id}", $updateData);

        $response->assertStatus(200)
            ->assertJson([
                'title' => $updateData['title'],
                'content' => $updateData['content'],
            ]);

        $this->assertDatabaseHas('posts', [
            'id' => $post->id,
            'title' => $updateData['title'],
            'content' => $updateData['content'],
        ]);
    }

    public function test_can_delete_post(): void
    {
        $post = Post::factory()->create();

        $response = $this->deleteJson("/api/posts/{$post->id}");

        $response->assertStatus(204);

        $this->assertSoftDeleted('posts', [
            'id' => $post->id,
        ]);
    }

    public function test_store_validation(): void
    {
        $response = $this->postJson('/api/posts', []);
        $response->assertStatus(422)
            ->assertJsonValidationErrors(['title', 'content']);
    }

    public function test_update_validation(): void
    {
        $post = Post::factory()->create();
        $response = $this->putJson("/api/posts/{$post->id}", []);
        $response->assertStatus(422)
            ->assertJsonValidationErrors(['title', 'content']);
    }
}
```

## 4. テストの実行

以下のコマンドでテストを実行できます。
```php artisan test tests/Feature/Api/PostTest.php```

※ RefreshDatabaseを使うとデータが毎回削除されます。DBをテスト環境とローカルで分けたい場合などは別途設定が必要です。
設定参考：https://qiita.com/mitashun/items/8b200c0b8c7080471ff6

## まとめ

この記事では、LaravelのFeatureテストの基本的な実装方法について説明しました。
実際の開発では、より複雑なテストケースや、モックを使用したテストなども必要になってきますが、基本的なテストの書き方として参考になれば幸いです。
(この記事はAIに壁打ちしながら作成したものとなります。）

## 参考リンク

- [Laravel テストドキュメント](https://readouble.com/laravel/10.x/ja/testing.html)