
Factory类必须继承Factory基类且定义$model
不继承Factory或漏写$model属性,调用时会报Call to undefined method factory()或Model not found。Laravel 8+ 强制要求显式声明模型类,不能靠命名推测。
实操建议:
-
$model必须是完整命名空间路径,比如App\Models\User,不能只写User - 工厂类名需与模型名一致(如
UserFactory对应User),否则factory(User::class)无法自动发现 - 若使用PHP 8+,可在构造函数中用
public function __construct(protected User $model)替代$model属性,但define()方法仍需返回数组
define()里别直接调用fake()静态方法
常见错误是写成fake()->name,这会导致每次生成实例都复用同一个Faker\Generator实例,字段值重复或上下文错乱。正确做法是通过闭包参数接收Faker\Generator实例。
实操建议:
- 必须用
function (Faker\Generator $faker) { return [...]; }形式定义,$faker由框架注入,保证每次调用独立 - 避免在
define()外层提前调用fake(),比如$faker = fake(); define(fn() => ['name' => $faker->name])——这会破坏数据随机性 - 需要条件逻辑时,闭包内可安全使用
$faker->optional()->sentence()等链式调用
调用create()前必须先for()或count()指定数量
直接调用UserFactory::new()->create()只会创建1条记录;想批量插入却忘了count(5),结果测试数据不足,断言失败。更隐蔽的问题是:没加for()关联时调用create(),外键字段为null导致数据库约束报错。
实操建议:
- 单条:用
UserFactory::new()->create() - 多条:用
UserFactory::new()->count(3)->create(),不是create(3) - 关联模型:用
UserFactory::new()->for(Post::factory())->create(),注意for()参数必须是另一个Factory实例,不能传模型对象 - 调试时加
dd()确认返回值是集合还是单个模型:create()返回模型实例,count(n)->create()返回Illuminate\Database\Eloquent\Collection
测试中用RefreshDatabase但数据仍残留?检查是否漏了use DatabaseMigrations
工厂数据写入后没被清空,常因测试类用了RefreshDatabase trait 却没配DatabaseMigrations,导致迁移未重跑、旧表结构残留,新工厂数据插入失败或被忽略。
实操建议:
- 单元测试(
TestCase)优先用use RefreshDatabase;,它会在每个测试前后重建内存数据库(Sqlite)或清空真实库表 - 功能测试(
BrowserTestCase)必须用use DatabaseMigrations;,否则artisan migrate:fresh不执行,工厂依赖的表可能不存在 - 运行测试前手动执行
php artisan migrate:fresh --seed能暴露工厂定义问题,比如字段名拼错导致SQLSTATE[HY000]: General error
工厂最易被忽略的是状态(state)复用和延迟求值。比如定义了admin()状态但没在create()里显式调用state(new AdminState()),或者把now()写死在define()数组里,导致所有记录时间戳完全相同。这些细节不报错,但会让测试行为不可预测。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











