Класс Factory
Класс Factory в Laravel позволяет создавать модели с тестовыми данными для использования в тестах и сидерах. Он предоставляет удобный способ генерации большого количества записей с реалистичными значениями полей. Фабрики определяют структуру данных через метод definition, где для каждого поля задаётся значение или генератор Faker. Основные методы фабрики: make - создаёт модель без сохранения в базу данных, create - создаёт и сохраняет модель, count - задаёт количество создаваемых записей, state - позволяет переопределить значения полей для конкретного состояния, sequence - создаёт последовательность значений для поля.
Создание фабрики
Для создания фабрики используется Artisan-команда:
Фабрика будет создана в директории database/factories. Рассмотрим пример фабрики для модели Article:
<?php
namespace Database\Factories;
use App\Models\Article;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
class ArticleFactory extends Factory
{
protected $model = Article::class;
public function definition(): array
{
return [
'user_id' => User::factory(),
'title' => $this->faker->sentence(),
'text' => $this->faker->paragraphs(3, true),
'status' => $this->faker->randomElement(['draft', 'published']),
'views' => $this->faker->numberBetween(0, 1000),
'is_public' => $this->faker->boolean(),
'created_at' => $this->faker->dateTimeBetween('-1 year'),
];
}
}
Создание моделей
Метод make создаёт экземпляры моделей без сохранения в базу данных:
<?php
use App\Models\Article;
use Database\Factories\ArticleFactory;
$article = Article::factory()->make();
echo $article->title;
Результат выполнения кода:
"Voluptatem ut est voluptatem."
Метод create создаёт и сохраняет модель в базе данных:
<?php
use App\Models\Article;
use Database\Factories\ArticleFactory;
$article = Article::factory()->create();
echo $article->id;
echo $article->title;
Результат выполнения кода:
1
"Voluptatem ut est voluptatem."
Создание нескольких записей
Метод count позволяет указать количество создаваемых записей:
<?php
use App\Models\Article;
use Database\Factories\ArticleFactory;
$articles = Article::factory()->count(3)->create();
foreach ($articles as $article) {
echo $article->title;
}
Результат выполнения кода:
"Voluptatem ut est voluptatem."
"Quisquam est qui dolorem."
"Est voluptatem ut voluptatem."
Переопределение значений
Можно передать массив значений для переопределения полей:
<?php
use App\Models\Article;
use Database\Factories\ArticleFactory;
$article = Article::factory()->create([
'title' => 'Custom title',
'status' => 'published',
]);
echo $article->title;
echo $article->status;
Результат выполнения кода:
"Custom title"
"published"
Состояния фабрики
Метод state позволяет определить различные состояния модели. Добавим состояние для опубликованных статей в фабрику:
<?php
namespace Database\Factories;
use App\Models\Article;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
class ArticleFactory extends Factory
{
protected $model = Article::class;
public function definition(): array
{
return [
'user_id' => User::factory(),
'title' => $this->faker->sentence(),
'text' => $this->faker->paragraphs(3, true),
'status' => 'draft',
'views' => $this->faker->numberBetween(0, 1000),
'is_public' => false,
];
}
public function published(): static
{
return $this->state([
'status' => 'published',
'is_public' => true,
]);
}
}
Использование состояния:
<?php
use App\Models\Article;
use Database\Factories\ArticleFactory;
$article = Article::factory()->published()->create();
echo $article->status;
echo $article->is_public;
Результат выполнения кода:
"published"
1
Последовательность значений
Метод sequence позволяет задать последовательность значений для поля при создании нескольких записей:
<?php
use App\Models\Article;
use Database\Factories\ArticleFactory;
$articles = Article::factory()
->count(3)
->sequence(
['status' => 'draft'],
['status' => 'published'],
['status' => 'archived'],
)
->create();
foreach ($articles as $article) {
echo $article->status;
}
Результат выполнения кода:
"draft"
"published"
"archived"
Связи между моделями
Метод has используется для создания связанных моделей. Например, создадим статью с тремя комментариями:
<?php
use App\Models\Article;
use App\Models\Comment;
use Database\Factories\ArticleFactory;
$article = Article::factory()
->has(Comment::factory()->count(3))
->create();
echo $article->comments->count();
Результат выполнения кода:
3
Метод for используется для указания родительской модели:
<?php
use App\Models\Article;
use App\Models\User;
use Database\Factories\ArticleFactory;
$user = User::factory()->create();
$article = Article::factory()
->for($user)
->create();
echo $article->user_id === $user->id;
Результат выполнения кода:
1
Использование в тестах
Рассмотрим пример использования фабрик в тестах:
<?php
namespace Tests\Feature;
use App\Models\Article;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class ArticleTest extends TestCase
{
use RefreshDatabase;
public function test_articles_list(): void
{
$user = User::factory()->create();
Article::factory()
->count(3)
->published()
->for($user)
->create();
$response = $this->actingAs($user)
->get('/api/articles');
$response->assertOk();
$response->assertJsonCount(3);
}
public function test_article_creation(): void
{
$user = User::factory()->create();
$data = Article::factory()->make()->toArray();
$response = $this->actingAs($user)
->post('/api/articles', $data);
$response->assertCreated();
$this->assertDatabaseHas('articles', [
'title' => $data['title'],
]);
}
}