creating-factories
Create Laravel model factories with type-safe state methods for generating test data. Use when creating factories, generating test data, seeding databases, or when user mentions factories, test data, fake data, or model factories.
When & Why to Use This Skill
This Claude skill automates the creation of type-safe Laravel model factories designed for robust test data generation. It enforces strict PHP standards, including final classes and PHP 8 attributes, to ensure your database seeders and test suites are maintainable, realistic, and PHPStan-compliant.
Use Cases
- Generating realistic mock data for Laravel unit and feature tests to ensure comprehensive code coverage.
- Creating composable state methods to easily simulate complex business scenarios like 'admin users', 'expired subscriptions', or 'published posts'.
- Seeding development and staging databases with high-quality, consistent data for manual testing and UI development.
- Standardizing factory codebases across a team to meet strict quality standards, including PHPStan level 8 and strict type coverage.
| name | creating-factories |
|---|---|
| description | Create Laravel model factories with type-safe state methods for generating test data. Use when creating factories, generating test data, seeding databases, or when user mentions factories, test data, fake data, or model factories. |
Create Laravel Model Factories
Create model factories with type-safe state methods for generating test data. Factories produce realistic model instances for testing, with composable state methods that configure specific scenarios like admin users or unpublished posts.
File Structure
Factories are stored in the database/factories directory:
database/factories/{Model}Factory.php
Examples:
database/factories/UserFactory.phpdatabase/factories/OrderFactory.phpdatabase/factories/ProductFactory.php
Core Conventions
1. Factory Structure
<?php
declare(strict_types=1);
namespace Database\Factories;
use App\Models\{Model};
use Illuminate\Database\Eloquent\Factories\Factory;
use Override;
/**
* @extends Factory<{Model}>
*/
final class {Model}Factory extends Factory
{
protected $model = {Model}::class;
#[Override]
public function definition(): array
{
return [
'field' => fake()->word(),
];
}
public function stateName(): self
{
return $this->state(fn (array $attributes): array => [
'field' => 'specific-value',
]);
}
}
Key Requirements:
- Always include
declare(strict_types=1); - Use
final classmodifier - Extend
Factorybase class - Add
@extends Factory<Model>PHPDoc - Set
protected $modelproperty - Use
#[Override]ondefinition()method - Type hint state methods returning
self - Use
fake()helper for fake data
2. Definition Method
#[Override]
public function definition(): array
{
return [
'name' => fake()->name(),
'email' => fake()->unique()->safeEmail(),
'password' => Hash::make('password'),
'created_at' => now(),
];
}
3. State Methods
public function unverified(): self
{
return $this->state(fn (array $attributes): array => [
'email_verified_at' => null,
]);
}
public function admin(): self
{
return $this->state(fn (array $attributes): array => [
'role' => 'admin',
]);
}
Examples
Example 1: User Factory
<?php
declare(strict_types=1);
namespace Database\Factories;
use App\Models\User;
use App\Support\Localisation\Facades\Localisation;
use App\Support\TwoFactorAuthentication\Facades\TwoFactorAuthentication;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
use Override;
/**
* @extends Factory<User>
*/
final class UserFactory extends Factory
{
protected $model = User::class;
#[Override]
public function definition(): array
{
return [
'name' => fake()->name(),
'email' => fake()->unique()->safeEmail(),
'language' => Localisation::getDefaultLocale(),
'password' => Hash::make('password'),
'two_factor_secret' => null,
'two_factor_recovery_codes' => null,
'remember_token' => Str::random(10),
'avatar_path' => null,
'email_verified_at' => now(),
'two_factor_confirmed_at' => null,
];
}
public function unverified(): self
{
return $this->state(fn (array $attributes): array => [
'email_verified_at' => null,
]);
}
public function withTwoFactorAuth(): self
{
return $this->state(fn (array $attributes): array => [
'two_factor_secret' => TwoFactorAuthentication::generateSecretKey(),
'two_factor_recovery_codes' => ['recovery-code-1', 'recovery-code-2'],
'two_factor_confirmed_at' => now(),
]);
}
public function withUnconfirmedTwoFactorAuth(): self
{
return $this->state(fn (array $attributes): array => [
'two_factor_secret' => TwoFactorAuthentication::generateSecretKey(),
'two_factor_recovery_codes' => ['recovery-code-1', 'recovery-code-2'],
]);
}
public function withAvatar(): self
{
return $this->state(fn (array $attributes): array => [
'avatar_path' => UploadedFile::fake()->image('avatar.jpg')->storePublicly('avatars', 'public'),
]);
}
}
Example 2: Factory with Relationships
<?php
declare(strict_types=1);
namespace Database\Factories;
use App\Models\Order;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
use Override;
/**
* @extends Factory<Order>
*/
final class OrderFactory extends Factory
{
protected $model = Order::class;
#[Override]
public function definition(): array
{
return [
'user_id' => User::factory(),
'total' => fake()->numberBetween(1000, 100000),
'status' => 'pending',
'notes' => fake()->sentence(),
];
}
public function completed(): self
{
return $this->state(fn (array $attributes): array => [
'status' => 'completed',
'completed_at' => now(),
]);
}
public function cancelled(): self
{
return $this->state(fn (array $attributes): array => [
'status' => 'cancelled',
'cancelled_at' => now(),
]);
}
public function forUser(User $user): self
{
return $this->state(fn (array $attributes): array => [
'user_id' => $user->id,
]);
}
}
Example 3: Factory with Enums
<?php
declare(strict_types=1);
namespace Database\Factories;
use App\Enums\PostStatus;
use App\Models\Post;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
use Override;
/**
* @extends Factory<Post>
*/
final class PostFactory extends Factory
{
protected $model = Post::class;
#[Override]
public function definition(): array
{
return [
'user_id' => User::factory(),
'title' => fake()->sentence(),
'body' => fake()->paragraphs(3, true),
'status' => PostStatus::Draft,
'published_at' => null,
];
}
public function published(): self
{
return $this->state(fn (array $attributes): array => [
'status' => PostStatus::Published,
'published_at' => now(),
]);
}
public function draft(): self
{
return $this->state(fn (array $attributes): array => [
'status' => PostStatus::Draft,
'published_at' => null,
]);
}
}
Using Factories
In Tests
// Create single model
$user = User::factory()->create();
// Create with attributes
$user = User::factory()->create([
'email' => 'test@example.com',
]);
// Create with state
$user = User::factory()->unverified()->create();
// Create multiple
$users = User::factory()->count(10)->create();
// Make without persisting
$user = User::factory()->make();
// Chain states
$user = User::factory()
->unverified()
->withTwoFactorAuth()
->create();
In Seeders
User::factory()->count(100)->create();
Order::factory()
->count(50)
->completed()
->create();
Anti-Patterns
❌ Don't Do This
// Don't skip @extends PHPDoc
final class UserFactory extends Factory // ❌ Missing @extends
// Don't skip #[Override] on definition()
public function definition(): array // ❌ Missing #[Override]
// Don't skip type hint on state methods
public function unverified() // ❌ Type hint return as self
{
return $this->state([...]);
}
// Don't use actual data in definition()
public function definition(): array
{
return [
'email' => 'test@example.com', // ❌ Use fake()
];
}
// Don't forget $model property
final class UserFactory extends Factory
{
// ❌ Missing protected $model
}
// Don't use mutable class
class UserFactory extends Factory // ❌ Use final class
✅ Do This Instead
// Include @extends PHPDoc
/**
* @extends Factory<User>
*/
final class UserFactory extends Factory
// Use #[Override] on definition()
#[Override]
public function definition(): array
// Type hint state methods
public function unverified(): self
{
return $this->state(fn (array $attributes): array => [...]);
}
// Use fake() helper
public function definition(): array
{
return [
'email' => fake()->safeEmail(),
];
}
// Set $model property
protected $model = User::class;
// Use final class
final class UserFactory extends Factory
Quality Standards
- All factories must pass PHPStan level 8
- 100% type coverage required
- Code formatted with Pint
- Refactored with Rector
- Use
fake()for all generated data - Provide useful state methods for common scenarios