Laravel5.3ユニットテストでテスト用DBを使う方法~要注意事項付き~

ユニットテストを行うときは本番用のDBに影響がないように、
テスト用のDBやテスト用のデータを用意してテストをしたいと思います。

それをLaravelで行う方法をまとめてみました。


## 環境

CentOS7.0
nginx 1.10
MySQL 5.7
PHP7.1
Larabel 5.3


# テスト用のデータを使う

今回はModelFactoryを使ってテスト用のデータを作って使ってみました。

## 手順１：database/factories/ModelFactory.php

テスト用データを２件作る。
（今回は説明のため２件作ったが１件〜で作って大丈夫。）

```ModelFactory.php
$factory->defineAs(App\Post::class, 'first', function (Faker\Generator $faker) {
    return [
        'title' => 'テストタイトル1',
        'content' => 'テスト本文1',
        'created_at' => "2017-02-02 10:10:53",
    ];
});

$factory->defineAs(App\Post::class, 'second', function (Faker\Generator $faker) {
    return [
        'title' => 'テストタイトル2',
        'content' => 'テスト本文2',
        'created_at' => "2017-02-03 10:10:53",
    ];
});
```

**defineAs()メソッド**を使用すれば、名前を指定してデータを扱える。

## 手順２：TopicsTest.php

テストファイル（今回はTopicsTest.php）にテストコードを書く。

```TopicsTest.php
class TopicsTest extends TestCase
{
    use DatabaseMigrations;

    public function testトピックスデータを取得()
    {
        $data1 = factory(\App\Topics::class, 'first')->create()->toArray();
        $data2 = factory(\App\Topics::class, 'second')->create()->toArray();
        $expected[] = $data1;
        $expected[] = $data2;

        $this->topics = new Topics;
        $result = $this->topics->fetchAllTopics();

        $this->assertEquals($expected, $result);
    }
```

###### $data1,$data2の説明。
factory()メソッドの第2引数にModelFactoryで指定した名前を使ってデータを指定できる。
また、第３引数に（第２引数が無い場合は、第２引数に）作りたい数を入れればその数のデータを作れる。


# テスト用DBを使用するように設定する

## 手順１：config/database.php

標準で記述されているsqliteの「インメモリ機能」を利用するドライバを追加する。

```database.php
'connections' => [

     　　　　 （略）

        'testing' => [
            'driver' => 'sqlite',
            'database' => ':memory:',
            'prefix' => '',
            'options' => [
                PDO::ATTR_PERSISTENT => true,
            ],
        ],

    ],
```

## 手順２：phpunit.xml

.envファイルを使って接続先を変更するため、phpunit.xmlに下記を追記。

```phpunit.xml
<php>
        <env name="APP_ENV" value="testing"/>
        <env name="CACHE_DRIVER" value="array"/>
        <env name="SESSION_DRIVER" value="array"/>
        <env name="QUEUE_DRIVER" value="sync"/>
        <env name="DB_CONNECTION" value="testing"/>　　　// ここ。valueの所に先ほどdatabase.phpで指定したドライバ名を追加。
    </php>
```

## 手順３：TopicsTest.php

テストファイルに下記を記述。
（今回はTopicsTest.php）

```
class TopicsTest extends TestCase
{
    use DatabaseMigrations;
```

これでテスト用のデータベースが使用できるようになる。

## 注意

TopicsTest.phpにuse DatabaseMigrations;を記述しただけの段階でphpunitを実行してしまうと、**確認環境のDBがすっ飛ぶので要注意**。（作ったテーブルがテーブル毎見事になくなった。笑）

調べてみると、これをしてしまうと全てのmigrationのRunがY→Nになっていた。

```
$ php artisan migrate:status
+------+------------------------------------------------+
| Ran? | Migration                                      |
+------+------------------------------------------------+
| N    | 2014_10_12_000000_create_users_table           |
| N    | 2014_10_12_100000_create_password_resets_table |
| N    | 2017_01_12_164933_create_topics_table          |
+------+------------------------------------------------+
```

なので、

```
use DatabaseMigrations;
```

を使う際は、テストに利用するデータベースの接続先を追加してから。
（**手順の１と２をきちんとやってから！！！！！**）



## おまけ

sqliteドライバが使えないということがあったので、その対応も書いておく。

エラー文↓

```
Symfony\Component\Debug\Exception\FatalThrowableError: Class 'Doctrine\DBAL\Driver\PDOSqlite\Driver' not found
```

> Laravelをインストールして、composer install した時点で
> “doctrine/dbal”もインストールされるべきだと思うんだけど…
> なんで、laravel のcomposer の依存関係に入ってないんだろう？釈然としない気持ち

[artisan migrate で dropColumnがエラーになりハマる – ララ帳](https://laravel10.wordpress.com/2015/02/27/dropcolumn%E3%81%8C-class-doctrinedbaldriverpdosqlitedriver-not-found-%E3%82%A8%E3%83%A9%E3%83%BC%E3%81%AB%E3%81%AA%E3%82%8B/)より

同感。笑
入れといてくれよって思ったけど、文句を言ってないで入れてみる。


```
$ composer require doctrine/dbal
```

これで解決。


以上、Laravel5.3ユニットテストでテスト用DBを使う方法でした。！
要注意事項には気をつけて使用してください！


# 参考

書籍「Laravelリファレンス: Web職人好みの新世代PHPフレームワーク」