Laravel Factoryでテストデータを生成する基本フロー

Laravel FactoryはEloquentモデルに紐づくダミーデータを、テストやシーディングで大量生成する仕組みです。基本は「definitionで初期値を決め、モデルのfactory()からcreate()make()で吐き出す」だけ。この構造はLaravel 8以降で一貫しています。

definitionメソッドでカラムの初期値を定義する

Factoryクラスはdefinition()の実装が必須で、返した連想配列が1レコード分の初期値になります。値はFakerで生成するのが定石です。

public function definition(): array
{
    return [
        'name' => fake()->name(),
        'email' => fake()->unique()->safeEmail(),
    ];
}

注意したいのがunique()です。ユニーク制約のあるカラムで付け忘れると、大量生成時に値が衝突してQueryExceptionで落ちます。

factory()メソッドとcreate・makeの使い分け

モデルにHasFactoryトレイトがあればUser::factory()でインスタンスを取得できます。分岐はここから。make()はメモリ上にモデルを作るだけでDBには書き込みません。一方create()は実際にINSERTし、永続化されたモデルを返します。

純粋にロジックだけ検証するならmake()、リレーションや保存後のIDが要るならcreate()です。User::factory()->count(3)->create()のように件数も指定できます。ただしcreate()はDBを触るぶんテストが遅くなるので、不要な場面で使わないのが勘所です。

リレーションとState定義で実データに近づける実践テクニック

単票のダミーで足りるのは初期段階だけです。実運用に近い検証では、親子関係を持つデータや特定条件のバリエーションが要ります。そこで効いてくるのがリレーション定義とStateです。

BelongsToリレーションとrecycleで重複レコードを防ぐ

子モデルのFactoryで親を指定すると、通常は子1件ごとに親も新規生成されます。100件の注文を作れば顧客も100件増える、という具合です。これを避けるのがrecycle()です。

内部ではBelongsToRelationshipgetRandomRecycledModel()でリサイクル対象から1件を再利用します(該当がなければcreate()にフォールバック)。共通の親を使い回したいときに、テーブルが不自然に膨らむのを防げます。

$user = User::factory()->create();
Order::factory()->count(50)->recycle($user)->create();

HasFactoryが見つからず生成に失敗する典型ケースと対処

現場で最も多いのがCall to undefined method AppModelsXxx::factory()です。大半はモデルにuse HasFactory;を書き忘れているだけで、php artisan make:model Xxx --factoryで生成すればトレイトは自動で入ります。

もう一つの落とし穴が命名規約です。FactoryはUserFactoryのようにモデル名+Factoryで自動解決されるため、クラス名がずれると見つかりません。規約から外す場合はUseFactory属性、またはモデル側のnewFactory()を上書きして明示的に紐づけます。

確認は簡単で、php artisan tinkerからUser::factory()->make()を実行し、属性入りのモデルが返れば結線は成功です。Artisanコマンド全般の作法はLaravel Artisanコマンドの作り方も参考になります。

カスタマイズに関するお問い合わせはこちら

    本記事のコード・挙動に関する記述は、Laravel 13.23.0 の実際のソースコードと照合して確認しています。