laravel ファクトリとSedderでデータベースをテスト

#はじめに
避けては通れないテスト作業。laravelでは簡単にテストができますので備忘録として投稿します。
モデルは`Models`というフォルダにて格納しています。
スクショはモデルの設計図になります。
![“スクリーンショット” 2021-02-19 23.32.29.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698439/907e9ccc-dcd4-5a1c-2d37-251dfd9fb61a.jpeg)


#投稿者の環境
MacBook Pro (13-inch, 2019, Two Thunderbolt 3 ports)
macOS Big Sur バージョン11.0.1
PHP 7.3.23
Laravel Framework 6.20.7

#下準備
`config\app.php`にある'faker_locale'を下記の様に修正して下さい。ダミーデータが日本語化されます。

```app.php
'faker_locale' => 'ja_JP',
```

#ファクトリの生成
ファクトリを作成することによりダミーデータを作成ができます。また、`--model=Postオプション`により、ファクトリが生成するモデルの名前を指定できます。このオプションは、生成するファクトリファイルへ指定モデル名を事前に設定します。モデルを作成していたら設定をして下さい。

```
ターミナル
php artisan make:factory PostFactory --model=Post
```


```Post.php
//階層 Models/Post.php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    public function comments()
    {
        // 投稿は複数のコメントを持つ
        return $this->hasMany('App\Models\Comment');
    }
 
}
```

#フェイカーの作成
マイグレーションファイルと照らし合わせながら作成します。カラムによりプロパティが変わりますので[こちらのチートシート](https://qiita.com/tosite0345/items/1d47961947a6770053af)を参考にして下さい。

```sample_faker.php
$data[] = [
        'name'     => $faker->name,            // 名前
        'zip'      => $faker->postcode,        // 郵便番号
        'pref'     => $faker->prefecture,      // 都道府県
        'city'     => $faker->city,            // 市
        'address'  => $faker->streetAddress,   // 住所
        'phone'    => $faker->unique()->phoneNumber,     // 電話番号
        'email'    => $faker->unique()->safeEmail,       // メール
        'birthday' => $faker->dateTimeBetween('-80 years', '-20years')
                            ->format('Y-m-d'), // 生年月日 (20〜80年前の日付)
        'score'    => $faker->numberBetween(1, 100), // 1〜100の数字
        'text'     => $faker->realText(20),    // ダミーテキスト 20文字
    ];
```

```PostFactory.php
<?php

/** @var \Illuminate\Database\Eloquent\Factory $factory */

use App\Models\Post; //Postモデルを参照してテストデータを作成。Modelsというフォルダに格納しているため
use Faker\Generator as Faker;
//  ↓ Post::classのPostはModelsフォルダのPostを参照
$factory->define(Post::class, function (Faker $faker) {
    return [
        'name' => $faker->name,    // 氏名
        'subject' => $faker->realText(16),    // realTextは日本語の投稿場合に必ず使用。
        'message' => $faker->realText(200),    // 200文字のテキスト
        'created_at' => $faker->date('Y-m-d H:i:s', 'now'),
        'updated_at' => $faker->date('Y-m-d H:i:s', 'now'),
        
    ];
});

```

```create_posts_table.php
//Postsマイグレーションファイル
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreatePostsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->timestamps();
            $table->string('name');
            $table->string('subject');
            $table->text('message');
           
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('posts');
    }
}
```

#Seederファイルの作成
Seederを作成することによって前述したファクトリのダミーデータを呼び出すことができる様になります。
SeederというのはDBのテスト以外でもく初期値やダミーデータ投入のための仕組みになります。
下記のコマンドを実行するとdatabase/seeds/以下にファイルが生成されます。また、PostsTableSeeder.phpを下記の様に編集して下さい。

```
ターミナル
php artisan make:seeder PostsTableSeeder
```

```PostsTableSeeder.php
<?php
use Illuminate\Database\Seeder;
 
class PostsTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
public function run()
    {
        
        factory(App\Models\Post::class, 50) //Postモデルを参照して尚且つ50個のダミーデータを作成
            ->create();
    }
}
```

#外部キーによるファクトリとSeederの設定
CommentにはPost_idという外部キーが割り当てられています。このままテストデータを作成しても

```
SQLSTATE[HY000]: General error: 1364 Field カラム名 doesn't have a default value
```
というエラーが発生します。そこで、リレーションを指定することにより外部キーにダミーデータを作成することができます。ファクトリを下記の様に編集します。[公式HP](https://readouble.com/laravel/6.x/ja/database-testing.html#writing-factories)の`リレーションと属性クロージャ`を参考にしました。

```CommentFactory.php
<?php

/** @var \Illuminate\Database\Eloquent\Factory $factory */

use App\Models\Comment;
use Faker\Generator as Faker;

$factory->define(Comment::class, function (Faker $faker) {
    return [
        'name' => $faker->name,
        'comment' => $faker->realText(200), 
        'post_id' => factory(App\Models\Post::class),//外部キーを参照
        'created_at' => $faker->date('Y-m-d H:i:s', 'now'),
        'updated_at' => $faker->date('Y-m-d H:i:s', 'now'),
    ];
});
```

```CommentsTableSeeder.php
<?php

use Illuminate\Database\Seeder;

class CommentsTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        factory(App\Models\Comment::class, 50)
            ->create();
    }
}

```
#最後に
database/seeds/DatabaseSeeder.phpを開いて、runメソッドに PostsTableSeeder を追加します。

```DatabaseSeeder.php
<?php

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run()
    {
        // $this->call(UsersTableSeeder::class);
        $this->call(PostsTableSeeder::class);
        $this->call(CommentsTableSeeder::class);
    }
}

```

```
ターミナル
$ composer dump-autoload
$ php artisan db:seed

ダミーデータを削除して再度作成したい場合
$ composer dump-autoload
$ php artisan migrate:refresh --seed

```
成功すると下記のスクショの様になりphpMyAdminにダミーデータが保存されます。
![“スクリーンショット” 2021-02-20 0.27.37.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698439/98b311a9-93b9-be13-e550-d71dcfec1404.jpeg)
![“スクリーンショット” 2021-02-20 0.28.29.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698439/f973e892-8aff-7add-b77f-4438771432ff.jpeg)

#参考URL
[データベースのテスト](https://readouble.com/laravel/6.x/ja/database-testing.html#writing-factories)
[参考Qiita](https://qiita.com/zaburo/items/56bc5d2f3377c3c50028)
[参考テスト](https://nodoame.net/archives/11572#vol4)