本文目录导读:

- 创建工厂
- 在模型中使用工厂
- 在测试中使用工厂
- 关联模型工厂
- 使用回调(After Making / After Creating)
- 使用 setUp() 和 RefreshDatabase
- 高级用法:多态关联
- 使用序列(Sequences)
- 使用现有数据补充
- 测试最佳实践
- 工厂生成自定义数据
- 常见问题解决
在 Laravel 中,测试夹具(Fixtures) 用于在测试运行前设置数据库状态,而 工厂(Factories) 是定义模型默认数据结构的工具,两者结合使用可以高效地创建测试数据。
以下是 Laravel 测试中使用工厂的完整指南:
创建工厂
生成工厂类
php artisan make:factory UserFactory
定义工厂(database/factories/UserFactory.php)
<?php
namespace Database\Factories;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
class UserFactory extends Factory
{
protected $model = User::class;
public function definition(): array
{
return [
'name' => fake()->name(),
'email' => fake()->unique()->safeEmail(),
'email_verified_at' => now(),
'password' => bcrypt('password'), // 默认密码
'remember_token' => Str::random(10),
'role' => 'user',
];
}
// 自定义状态(State)
public function admin(): static
{
return $this->state(fn (array $attributes) => [
'role' => 'admin',
]);
}
public function unverified(): static
{
return $this->state(fn (array $attributes) => [
'email_verified_at' => null,
]);
}
}
在模型中使用工厂
在模型中引入 HasFactory trait:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
use HasFactory;
// ...
}
在测试中使用工厂
简单创建单条数据
use App\Models\User;
public function test_user_can_be_created()
{
$user = User::factory()->create();
$this->assertDatabaseHas('users', [
'email' => $user->email,
]);
}
创建多条数据
User::factory()->count(5)->create();
使用状态(State)
$admin = User::factory()->admin()->create(); $unverified = User::factory()->unverified()->create();
覆盖属性
$user = User::factory()->create([
'email' => 'custom@example.com',
]);
不创建(仅生成数据但不写入数据库)
$userData = User::factory()->make();
关联模型工厂
定义关联工厂(PostFactory)
class PostFactory extends Factory
{
protected $model = Post::class;
public function definition(): array
{
return [
'title' => fake()->sentence(),
'body' => fake()->paragraph(),
'user_id' => User::factory(), // 自动创建关联用户
];
}
}
在测试中创建关联数据
$post = Post::factory()->create(); // 会自动创建一个关联的User $post->user->name;
使用 has() 创建关联
$user = User::factory()
->has(Post::factory()->count(3))
->create();
// 创建了3篇关联文章
$user->posts()->count(); // 3
使用回调(After Making / After Creating)
public function definition(): array
{
return [
'title' => fake()->sentence(),
'user_id' => User::factory(),
];
}
public function configure(): static
{
return $this->afterCreating(function (Post $post) {
// 创建后执行逻辑,例如生成 slug
$post->update(['slug' => Str::slug($post->title)]);
});
}
使用 setUp() 和 RefreshDatabase
通常在测试类中使用 RefreshDatabase trait 让每次测试后重置数据库:
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class PostTest extends TestCase
{
use RefreshDatabase;
public function test_post_creation()
{
$user = User::factory()->create();
$response = $this->actingAs($user)
->post('/posts', [
'title' => 'Test Title',
'body' => 'Test Body',
]);
$response->assertStatus(201);
$this->assertDatabaseHas('posts', ['title' => 'Test Title']);
}
}
高级用法:多态关联
// ImageFactory
public function definition(): array
{
return [
'url' => fake()->imageUrl(),
'imageable_id' => Post::factory(),
'imageable_type' => Post::class,
];
}
使用序列(Sequences)
$users = User::factory()
->count(3)
->sequence(
['name' => 'User One'],
['name' => 'User Two'],
['name' => 'User Three'],
)
->create();
使用现有数据补充
$tenant = Tenant::first(); // 使用现有记录
Post::factory()->create([
'tenant_id' => $tenant->id,
]);
测试最佳实践
- ✅ 使用
RefreshDatabase而不是DatabaseTransactions,因为更可靠。 - ✅ 为每个测试清理数据,保持测试独立性。
- ✅ 使用有意义的 State(如
admin()、premium())。 - ✅ 避免硬编码 ID,使用工厂生成的关联。
工厂生成自定义数据
使用 Faker 支持:
public function definition(): array
{
return [
'phone' => fake()->phoneNumber(),
'date' => fake()->dateTimeBetween('-1 year', 'now'),
'status' => fake()->randomElement(['active', 'pending', 'disabled']),
];
}
常见问题解决
Q:工厂生成中文数据?
// config/app.php 中修改 'faker_locale' => 'zh_CN',
Q:工厂类找不到 HasFactory?
确保模型引入了:
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
use HasFactory;
}
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播