跳转到主内容
websoft网络软件专家 - 深耕网络技术,打造实用软件!

Laravel怎么使用模型工厂_Laravel如何编写测试数据【示例】

Laravel 8+工厂需置于database/factories/下且类名匹配(如UserFactory),嵌套子目录将导致自动发现失败;Laravel 9+起应使用User::factory()->count(5)->create()而非factory(User::class);unique()仅在同一工厂实例内有效,批量创建才保证唯一性;测试中需手动清理关联表或配置级联删除。 工厂类没被自动发现,
php artisan tinker
里调用
App\Models\User::factory()->create()
报错 Laravel 8+ 默认启用模型工厂自动发现,但前提是工厂文件得放在
database/factories
下,且类名要严格匹配模型名(如
UserFactory
对应
User
)。如果工厂类在子目录(比如
database/factories/User/UserFactory.php
),Laravel 就找不到它。 检查路径:必须是
database/factories/xxxFactory.php
,不能嵌套子文件夹 确认命名空间:Laravel 10 推荐用
use Database\Factories\UserFactory;
显式引入,而不是依赖自动发现 手动注册(临时救急):在
DatabaseFactory
的
configure()
方法里加
$this->factories([UserFactory::class]);
factory()->count(5)->create()
创建的数据没进数据库,或只插了 1 条 常见于 Laravel 9+,因为
factory()
辅助函数已被弃用,直接调用会触发 E_USER_DEPRECATED 警告,且在某些配置下实际执行的是空操作——尤其当你混用了旧写法和新工厂类时。 改用模型静态方法:
User::factory()->count(5)->create()
,这是当前唯一可靠方式 别再用
factory(User::class)->count(5)->create()
,它在 Laravel 9.2+ 已失效 如果用了
createMany()
,注意它返回的是集合而非模型实例数组,字段验证失败时不会抛异常,而是静默跳过 工厂里用
$this->faker->unique()->email
还是报
Integrity constraint violation: 1062 Duplicate entry
Faker
的
unique()
是懒加载的,只对同一工厂实例内连续调用有效。一旦你分多次调用
User::factory()->create()
(比如循环中),每次都是新实例,
unique()
不跨实例记忆。 批量创建时才安全:
User::factory()->count(10)->create()
,这时
unique()
能覆盖全部 10 次生成 单条创建需手动去重:用
retry()
或先查后插,例如
do { $email = $this->faker->email; } while (User::where('email', $email)->exists());
更稳的做法:在工厂里用
$this->faker->uuid . '@example.com'
,避开唯一性校验逻辑 测试中用工厂造数据,但
refreshDatabase
迁移后关联表数据还在 工厂本身不负责清理,它只管插入。如果你在测试里用
User::factory()->has(Post::factory()->count(3))->create()
,迁移回滚时只会清空
users
表,
posts
表里的记录还在,下次测试可能因外键约束失败。 确保迁移文件里定义了
foreignId
并启用
onDelete('cascade')
不要依赖工厂自动清理,测试前显式清空:
Post::truncate();
(慎用,注意顺序) 更推荐方案:在
TestCase
的
setUp()
里用
DB::table('posts')->delete();
,比 truncate 更安全,不重置自增 ID 工厂最麻烦的不是写法,是它和迁移、数据库状态、Faker 实例生命周期这三者的耦合——稍不注意,测试就变成“看运气跑通”。尤其在并行运行测试或使用内存数据库时,
unique()
和事务隔离级别会联合给你埋雷。

相关文章