Laravelでテストデータ作成 ファクトリ・シーダ

コーディングを完了しいざテストをはじめようとしても、テストデータを作成する必要がありますが

100件とか1,000件必要になると、1個1個作るのはかなりしんどいですよね。

Laravelでは、『ファクトリ』と『シーダ』という機能を利用して簡単に大量のデータが作成できますので、今回はこの手順をご紹介します。

Laravel8から記述方法が変わり、より便利になっています!今まで使っていなかった方は、ぜひこの文明の利器を享受していきましょう。

hasOneの場合やリレーションのあるモデルに対するテストデータ作成について、ググってもあまり記事が見当たらなかったのでこちらにまとめました。

ファクトリとシーダ

ファクトリとは

モデルを生成するための『工場(Factory)』と考えると分かりやすいと思います。

各項目にデータを代入し、モデルを自動で生成していきます。代入するは全て一律でなく、実際の名称をランダムに生成することもできます。

サンプルコードはこちら。Userクラスに対するファクトリを定義しています。

 namespace Database\Factories;

 use App\Models\User;
 use Illuminate\Database\Eloquent\Factories\Factory;
 use Illuminate\Support\Str;

 class UserFactory extends Factory
 {
     /**
      * ファクトリの対応するモデル名
      *
      * @var string
      */
     protected $model = User::class;
 /**  * モデルのデフォルト状態の定義  *  * @return array  */ 
 public function definition() {
     return [
         'name' => $this->faker->name(),
         'email' => $this->faker->unique()->safeEmail(),
         'email_verified_at' => now(),
         'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
         'remember_token' => Str::random(10),
     ]; }
 }

nameやemailの部分にはfakerを利用しています。これは、指定されたパラメータのテストデータを生成します。

例えばnameであれば'前田 舞'、'渡辺 直人'などのデータが作成されていきます。

日本語を利用する場合には、設定ファイルに下記の言語の指定が必要です。

'faker_locale' => env('APP_FAKER_LOCALE', 'ja_JP'),

もちろん固定値を代入すれば、すべてのモデルで同じ値を取ることも可能です。

シーダとは

『種をまく(seeder)』ことでテストデータの初期値設定に利用します。

クラスを準備しておけば、コマンド一つでルールに記載した内容のテストデータが作成されます。

こちらもUserモデルに対するシーダのサンプルをご紹介していきます。

namespace Database\Seeders;

use App\Models\User;
use Illuminate\Database\Seeder;

class UserSeeder extends Seeder
{
public function run()
 {
     User::factory()
             ->count(50)
             ->create();
 }
}

デフォルトで1つのメソッド、runのみ存在しています。このrunメソッドに記述した内容でテストデータが作成されます。

処理の内容としては

  • runメソッドにて、Userモデルに対するファクトリの利用を宣言
  • countにて実行回数を定義
  • 最後にcreate指示

これでシーダから先ほどのfactoryを呼び出して、countの引数(ここでは50個)のデータを作成します。

詳細な説明は本家サイトにありますので、こちらもご覧ください。

ファクトリを使用するモデルの生成

リレーションのあるファクトリ

例えば、このようなリレーションのあるテーブルがあったとします。

1対多のリレーション

Bookに関するテストをする場合にも、Uesrモデルのデータが必要になってきます。また、Bookを大量に作成する必要があるときなどにファクトリが使えると強力な武器になります。

リレーションの設定

まずはモデルのリレーションから作成から。

 namespace App\Models;

 class User extends Authenticatable
 {
  use HasFactory;

  public function books()
  {
      return $this->hasMany(Book::class);
  }
}

ファクトリを利用するには、モデルにてHasFactoryトレイトを宣言します。

Laravelでは「モデル名と一致するクラス+Factory」の命名規則に則ったクラスをDatabase\Factories名前空間内から検索します。

この規則を利用しない場合は、モデルのnewFactoryメソッドを上書きして、モデルの対応するファクトリのインスタンスを直接返すことができます。

use Database\Factories\Administration\FlightFactory;
 /**
 モデルの新しいファクトリインスタンスの作成
 *
 @return \Illuminate\Database\Eloquent\Factories\Factory
 */
 protected static function newFactory()
 {
 return FlightFactory::new();
 } 

ファクトリの作成

すでに作成済みのUserファクトリに続いて、Bookファクトリも作成します。

 namespace Database\Factories;

 use App\Models\Book;
 use Illuminate\Database\Eloquent\Factories\Factory;
 use Illuminate\Support\Str;

 class BookFactory extends Factory
 {
 protected $model = Book::class;
 /**
  * モデルのデフォルト状態の定義
  *
  * @return array
  */ 
 public function definition() {
     return [
         'name' => $this->faker->name(),
         'author' => $this->faker->name(),
     ]; }
 }

Bookファクトリでは「user_id」のデータを作成していません。この理由はシーダでご説明します。

class UserSeeder extends Seeder
 {

     public function run()
     {

     User::factory()
         ->count(50)
         ->has(
             Book::factory()
                 ->count(1)
                 ->state(function (array $attributes, User $user) {
                     return ['user_id' => $user->id];
                 })
         )
         ->create();
 }
 }

シーダにてUserファクトリを利用する際に、hasメソッドを使ってリレーションのあるモデルも生成します。

今回はhasManyリレーションを題材にしておりますが、countの数を1にすればhasOneリレーションの場合も対応できます。

Bookモデルの生成に必要なuser_idは、クロージャ―を使って「$user->id」を渡しています。これでUesrモデル作成時のidを用いて、外部キーであるBookモデルのuser_idが代入できます。

リレーションのあるファクトリを複数作成

例えば、このようなリレーションがあった場合

Uesrモデルに対し2つのモデルがリレーションを持つ場合

Userモデルに対して、「Bookモデル」「Profileモデル」がそれぞれ1対多のリレーション状態になっています。

Userモデルの生成に応じて、外部キーを持っているBookモデルとProfileモデルも作りたい場合のサンプルコードはこちらになります。hasメソッドをモデルの数だけ利用するという事ですね。

class UserSeeder extends Seeder
 {
     /**
      * Run the database seeds.
      *
      * @return void
      */
     public function run()
     {

     User::factory()
         ->count(50)
         ->has(
             Book::factory()
                 ->count(1)
                 ->state(function (array $attributes, User $user) {
                     return ['user_id' => $user->id];
                 })
         )->has(
             Profile::factory()
                 ->count(1)
                 ->state(function (array $attributes, User $user) {
                     return ['user_id' => $user->id];
                 })
         )
         ->create();
   }
 }

これで一気に50名のUserとそれに紐づく50個のBook、50個のプロフィールが作成されました!

テストケース作成と併せて使えば、テストデータ作成⇒テスト実行という一覧の流れを自動化することができます。一覧の流れを自動化し、回帰テストなど複数回繰り返すテストケースで力を発揮します。

これで『手間だな、、』と思ってテストを省略することなく、品質の向上に努めていきましょう。

Laravel8でのファクトリ/シーダの説明は以上になります。

コメントを残す