【Laravel】PHPUnitテスト用にDBを設定してデフォルトのDBを汚さなくする


# テスト用にDBを用意してテストを実行する

テスト実行するたびにDBが消えたりテストデータが登録されたりするのは鬱陶しいので
PHPUnit用にDBを用意してテスト実行時はそのDBを使用するようにしてみます

こちらも参考にしてください
つ [【Laravel】PHPUnitテスト用にSQLiteをDBに設定した際に気を付けるべきマイグレーションの記述と解決方法](https://qiita.com/sola-msr/items/80b0c0e0edb67a35d282)

# 実装例

## `config`ディレクトリ以下の`database.php`にtesting用の設定を追加

```diff:laravel\config\database.php
<?php

    /*
    |--------------------------------------------------------------------------
    | Database Connections
    |--------------------------------------------------------------------------
    |
    | Here are each of the database connections setup for your application.
    | Of course, examples of configuring each database platform that is
    | supported by Laravel is shown below to make development simple.
    |
    |
    | All database work in Laravel is done through the PHP PDO facilities
    | so make sure you have the driver for your particular database of
    | choice installed on your machine before you begin development.
    |
    */

    'connections' => [

        // -- 省略 -- //

        // 以下を追加する
+       'testing' => [
+           'driver'   => 'sqlite',
+           'database' => ':memory:', // SQLiteのインメモリ機能を使用
+           'prefix'   => '',
+           'options'  => [
+               // テストデータの永続化
+               PDO::ATTR_PERSISTENT => false,
+           ],
+       ],

    ],

```

SQLiteのインメモリ機能とは以下のような性質をもっているので、ユニットテスト向きっぽいです

> When this is done, no disk file is opened. Instead, a new database is created purely in memory. The database ceases to exist as soon as the database connection is closed. Every :memory: database is distinct from every other. So, opening two database connections each with the filename ":memory:" will create two independent in-memory databases.

以下Google翻訳
> これが行われると、ディスクファイルは開かれません。代わりに、新しいデータベースが純粋にメモリ内に作成されます。データベース接続が閉じられるとすぐにデータベースは存在しなくなります。 Every：memory：databaseは他のものとは異なります。そのため、それぞれ "：memory："というファイル名で2つのデータベース接続を開くと、2つの独立したインメモリデータベースが作成されます。

SQLiteの「In-Memory Databases」機能についての詳細は以下を参照
[In-Memory Databases](https://www.sqlite.org/inmemorydb.html)

## `phpunit.xml`にも同様`testing`用の設定を追加

```diff:laravel/phpunit.xml
        <env name="CACHE_DRIVER" value="array"/>
        <env name="SESSION_DRIVER" value="array"/>
        <env name="QUEUE_DRIVER" value="sync"/>
+       <env name="DB_CONNECTION" value="testing"/>
    </php>
</phpunit>

```

**※5.8系では以下のように記述**

```diff:laravel/phpunit.xml
    <php>
        <server name="APP_ENV" value="testing"/>
        <server name="BCRYPT_ROUNDS" value="4"/>
        <server name="CACHE_DRIVER" value="array"/>
        <server name="MAIL_DRIVER" value="array"/>
        <server name="QUEUE_CONNECTION" value="sync"/>
        <server name="SESSION_DRIVER" value="array"/>
+       <server name="DB_CONNECTION" value="testing"/>
    </php>
```

# テストコード実装例

```UserTest.php
<?php

namespace Tests\Unit;

use Tests\TestCase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use App\User;

class UserTest extends TestCase
{
    use RefreshDatabase;

    private $attributes;

    public function setUp()
    {
        parent::setUp();

        $this->attributes = [
            'name'     => 'テスト太郎',
            'mail'     => 'hoge@example.com',
            'password' => bcrypt('test'),
        ];
    }

    public function test_登録できる()
    {
        User::create($this->attributes);
        $this->assertDatabaseHas('users', $this->attributes);
    }

}
```

これで実DBを汚さず遠慮なくテストを実行できるようになりました

# 参考
- [Laravel5.3ユニットテストでテスト用DBを使う方法~要注意事項付き~ - Qiita](https://qiita.com/riritachibana/items/2d3018346727bc5acc13)
- [Laravel でテスト〜準備編 - Qiita](https://qiita.com/nunulk/items/95de71058cd8ddb80079)