laravel テストで使用するDBを作成してテストで使えるようにするまで

## 概要

- テストコード実行時にだけ接続するテーブルを用意して設定する方法をまとめる

## 方法

1. テスト用DBの作成
    1. 今回は手動で実施するがDockerなどで環境構築している場合、docker-compose.ymlなどに記載してコマンド一つで構築できるようにしたほうがいいかもしれない。
    1. MySQLにログインして下記SQL句を実行してテスト用DBを作成する。（筆者はlaravel_testingというDB名で作成した。）

        ```sql
        create database laravel_testing;
        ```

    1. `show databases;`を実行して正常にDBが作成されたことを確認する。

        ![Makefile_—_project.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/1e3db722-3e39-49eb-43e9-540401530457.png)

    1. 下記SQL句を実行して只今作成したDBの権限を設定する。（laravelの.envに記載されているDBアクセスユーザーが書き込みをできるようにする。）

        ```sql
        grant all on laravel_testing.* to MySQLユーザー名;
        ```

1. テスト用.envの作成
    1. 既に存在する.env.exampleをコピーして.env.testingを作成する。

        ```shell
        cp .env.example .env.testing
        ```

    1. 下記コマンドを実行して.env.testing用のAPP_KEYを発行する。

        ```shell
        php artisan key:generate --env=testing
        ```

    1. `DB_DATABASE`の値を`laravel_testing`に変更する。

        ```.env.testing
        APP_ENV=testing

        DB_DATABASE=laravel_testing
        ```

1. テスト時に使うDBの設定
    1. laravelのアプリケーションディレクトリ内にある`phpunit.xml`を開く。
    1. コメントアウトされている`<!-- <env name="DB_DATABASE" value=":memory:"/> -->`を修正して下記のように記載する。（こちらでテスト時に使用するDB名を設定している。）

        ```phpunit.xml
        <env name="DB_DATABASE" value="laravel_testing"/>
        ```

1. テストコードの記載
    1. あとは任意のFeatureテストコードにsetUp()関数を定義して下記のように記載すればテスト毎にマイグレーションとシーダーを実行してくれる。（トレイトの呼び出しもお忘れなく。シーダーを実行する時はRefreshDatabaseトレイトではなくDatabaseMigrationsトレイトを呼び出さないとダメなので注意）

        ```FooTest.php
        use DatabaseMigrations;
    
        public function setUp(): void
        {
            parent::setUp();
            
            Artisan::call('migrate:fresh --seed');
        }
        ```

    1. 筆者はFeatureテスト用のベースクラスを別途作成しそのクラスを各Featureクラスで継承するようにしている。
        - Featureテスト用のベースクラス

            ```FeatureBaseTestCase.php
            <?php
            
            namespace App\Tests;
            
            use Illuminate\Foundation\Testing\DatabaseMigrations;
            use Illuminate\Support\Facades\Artisan;
            use Tests\TestCase;
            
            class FeatureBaseTestCase extends TestCase
            {
                    use DatabaseMigrations;
                
                    public function setUp(): void
                    {
                        parent::setUp();
                        
                        Artisan::call('migrate:fresh --seed');
                    }
            }
            ```

        - Featureテストクラス

            ```PostContentControllerTest.php
            <?php
            
            namespace Tests\Feature\Content;
            
            use App\Tests\FeatureBaseTestCase;
            
            class PostContentControllerTest extends FeatureBaseTestCase
            {
            
                const URL = '/api/content';
            
                public function test_投稿内容が登録できる(): void
                {
                    $url = self::URL;
                    $requestBody = [
                        'content' => 'XXX',
                    ];
                
                    $response = $this->post($url, $requestBody);
                    $response->assertCreated();
                }
            }
            ```

## おまけ

- 単純にテスト時だけDBトランザクションを貼ってほしい場合、下記のようにDatabaseTransactionsクラスをuseしてあげればよいかも。

    ```php
    use Illuminate\Foundation\Testing\DatabaseTransactions;

    class FooTest extends TestCase {
        use DatabaseTransactions;
    }
    ```

## 参考文献

https://phpunit.readthedocs.io/en/9.5/configuration.html

https://phpunit.readthedocs.io/en/9.5/index.html

https://readouble.com/laravel/9.x/ja/testing.html

https://qiita.com/akkino_D-En/items/024661836b7570d78704