Factory 的 make() 仅创建内存对象,不写入数据库;create() 才调用 save() 持久化。非 Eloquent 类宜用闭包工厂或手动继承 Factory。避免 definition() 中循环调用 create(),改用 for() 或 make() 显式赋值。state() 仅用于字段补丁,副作用逻辑应放 afterCreating()。

Factory 生成的模型实例为什么没进数据库?
默认情况下 Factory 调用 make() 只构造内存对象,不持久化。这是最常被忽略的一点——你以为数据已写入,其实只是个空壳。
- 用
create()才会调用save()并写入数据库(需模型有对应数据表) -
make()适合做纯对象逻辑测试,比如验证 accessor、mutator 或自定义方法 - 若在测试中依赖数据库状态(如关联查询、软删除判断),必须用
create()或显式调用$model->save()
如何为非 Eloquent 类或自定义类型写 Factory?
Laravel 的 Illuminate\Database\Eloquent\Factories\Factory 默认绑定模型类,但你可以绕过它,直接用闭包工厂处理任意类型。
- 在
database/factories下新建文件(如UserSettingFactory.php),返回一个闭包:
use App\Models\UserSetting;
return [
'theme' => fake()->randomElement(['light', 'dark']),
'notifications_enabled' => fake()->boolean(),
'language' => fake()->locale(),
];
- 使用时:
$data = UserSettingFactory::new()->make();—— 这里UserSettingFactory是你手动定义的类,继承Factory并重写definition() - 关键点:不要强行让
Factory绑定无$table属性的类;优先考虑纯数组生成 + 手动构造实例
Factory 中调用其他 Factory 时的循环依赖怎么破?
比如 PostFactory 依赖 UserFactory::create(),而 UserFactory 又在某个字段里调用了 PostFactory::make(),就会报 Maximum function nesting level reached。
- 避免在
definition()里直接调用另一个 Factory 的create(),改用for()方法声明关系:
PostFactory::new()
->for(UserFactory::new()->state(['email' => 'test@example.com']))
->create();
- 若必须嵌套生成,用
make()+ 显式赋值代替自动关联: $user = UserFactory::new()->make(); $post = PostFactory::new()->make(['user_id' => $user->id]);- 检查
factory.php是否误将某个 Factory 注册为单例(Laravel 9+ 已弃用全局factory()函数,别混用旧写法)
Factory 状态(state)和场景(scenario)容易混淆的地方
state() 是字段补丁,configure() 或 afterCreating() 才是控制副作用的入口。很多人把状态当成“执行逻辑”的钩子。
-
state('published')应只修改字段(如['status' => 'published']),别在里面调用save()或发事件 - 真正需要“创建后动作”的地方,用
afterCreating():
PostFactory::new()
->afterCreating(function (Post $post) {
$post->tags()->attach([1, 2]);
})
->create();
- 多个状态叠加时注意覆盖顺序:
state(['a'=>1])->state(['b'=>2])没问题,但state(['a'=>1])->state(['a'=>2])后者会覆盖前者
复杂模型的 Factory 很容易变成黑盒——尤其当大量使用 for()、has() 和 afterCreating() 嵌套时,建议每个 Factory 文件顶部加注释说明「哪些字段由谁提供」「哪些关联强制存在」「哪些状态不可共存」。











