【Laravel】APIテスト

# はじめに
[【簡単】LaravelでAPIの実装](https://qiita.com/miya1221/items/868a047950f04cd5e80d)の続きでテストコードを簡単に追加

# 内容

- testファイル作成

```
$  php artisan make:test ApiBlogControllerTest
```

```ApiBlogControllerTest.php
<?php

namespace Tests\Feature;

use App\Models\Blog;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;

class ApiBlogControllerTest extends TestCase
{
    use RefreshDatabase;

    public function testIndex_一覧取得()
    {
        Blog::factory()->count(5)->create();
        $response = $this->get('/api/blogs');

        $response->assertStatus(200)
            ->assertJsonStructure([
                'status',
                'blogs',
            ]);
    }

    public function testStore_記事作成()
    {
        $blogData = [
            'title' => 'Test Blog',
            'article' => 'This is a test article.',
        ];

        $response = $this->post('/api/blogs', $blogData);

        $response->assertStatus(201)
            ->assertJsonStructure([
                'status',
                'message',
                'blog',
            ]);
        $this->assertDatabaseHas('blogs', $blogData);
    }

    public function testShow_詳細取得()
    {
        $blog = Blog::factory()->create();

        $response = $this->get("/api/blogs/{$blog->id}");

        $response->assertStatus(200)
            ->assertJsonStructure([
                'status',
                'blog',
            ]);
    }

    public function testShow_記事が見つからない()
    {
        $this->get('/api/blogs/999')
        ->assertStatus(404)
            ->assertJson([
                'message' => 'Blog not found',
            ]);
    }

    public function testUpdate_記事更新()
    {
        $blog = Blog::factory()->create();
        $updatedData = [
            'title' => 'Updated Title',
            'article' => 'Updated Article',
        ];

        $response = $this->put("/api/blogs/{$blog->id}", $updatedData);

        $response->assertStatus(200)
            ->assertJsonStructure([
                'message',
                'data',
            ]);
        $this->assertDatabaseHas('blogs', $updatedData);
    }

    public function testUpdate_記事が見つからない()
    {
        $this->putJson('/api/blogs/999', [
            'title' => 'updated title',
            'article' => 'updated article',
        ])
            ->assertStatus(404)
            ->assertJson([
                'message' => 'Blog not found',
            ]);
    }


    public function testDestroy_記事削除()
    {
        $blog = Blog::factory()->create();

        $response = $this->delete("/api/blogs/{$blog->id}");

        $response->assertStatus(200)
            ->assertJson([
                'message' => 'Blog deleted successfully',
            ]);
        $this->assertDatabaseMissing('blogs', ['id' => $blog->id]);
    }

    public function testDestroy_記事が見つからない()
    {
        $this->delete('/api/blogs/999')
        ->assertStatus(404)
            ->assertJson([
                'message' => 'Blog not found',
            ]);
    }
}

```
- 結果

![スクリーンショット 2024-02-18 20.46.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/923146/e5568a2d-25d0-b5e9-d042-b96cdb8cae9d.png)


- リクエストに対するテスト（バリデーション）

```
$ php artisan make:test StoreBlogRequestTest
```

```StoreBlogRequestTest.php
<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;
use App\Http\Requests\StoreBlogRequest;
use Faker\Factory;

class StoreBlogRequestTest extends TestCase
{
    use RefreshDatabase;
    use WithFaker;


    public function testValidation_OK()
    {
        $data = [
            'title' => $this->faker->title,
            'article' => $this->faker->paragraph,
        ];

        $response = $this->postJson('/api/blogs', $data);

        $response->assertStatus(201);

        $this->assertDatabaseHas('blogs', $data);
    }

    public function testTitle_必須NG()
    {
        $response = $this->postJson('/api/blogs', [
            'title' => '',
            'article' => '記事内容',
        ]);

        $response->assertStatus(400);

        $response->assertJsonValidationErrors([
            'title' => 'タイトルは必須です',
        ]);
    }

    public function testArticle_必須NG()
    {
        $response = $this->postJson('/api/blogs', [
            'title' => 'タイトル',
            'article' => '',
        ]);

        $response->assertStatus(400);

        $response->assertJsonValidationErrors([
            'article' => '記事は必須です',
        ]);
    }

    public function testTitle_文字数NG()
    {
        $title = str_repeat('a', 21);
        $response = $this->postJson('/api/blogs', [
            'title' => $title,
            'article' => $this->faker->paragraph,
        ]);

        $response->assertStatus(400);
        $response->assertJsonValidationErrors([
            'title' => 'タイトルは20文字以内です',
        ]);
    }


    public function testArticle_文字数NG()
    {
        $article = str_repeat('a', 256);
        $response = $this->postJson('/api/blogs', [
            'title' => $this->faker->title,
            'article' => $article,
        ]);

        $response->assertStatus(400);
        $response->assertJsonValidationErrors([
            'article' => '記事は255文字以内です',
        ]);
    }
}

```

- 結果

![スクリーンショット 2024-02-21 21.06.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/923146/a475afe7-e78e-64db-5062-dc33620f60df.png)

# まとめ
サクッと簡単にテストコード追記しました。

# 参考
- [Laravel 10.x テスト: テストの準備](https://readouble.com/laravel/10.x/ja/testing.html)
- [Testing: Getting Started](https://laravel.com/docs/10.x/testing)