laracasts/testdummy
Generate Eloquent models for tests without factories. Define blueprints and quickly create/build records with sensible defaults, relationships, and overrides—ideal for speeding up Laravel test setup and prototyping with minimal boilerplate.
Installation:
composer require --dev laracasts/testdummy
No additional configuration is required if using Laravel 5.5+ (auto-discovery).
First Use Case:
Generate a factory for a model (e.g., User):
php artisan make:factory UserFactory --model=User
Use it in a test:
use Laracasts\TestDummy\Factory;
$user = Factory::for(User::class)->create();
Where to Look First:
database/factories/ (auto-generated or manually defined).tests/Feature/ or tests/Unit/ for integration examples.Basic Model Creation:
Replace manual Model::create() calls with TestDummy:
// Before
$user = User::create(['name' => 'John', 'email' => 'john@example.com']);
// After
$user = Factory::for(User::class)->create(['name' => 'John']);
Relationships: Define relationships in factories and chain them:
// UserFactory.php
public function withPosts()
{
return $this->afterCreating(function ($user) {
Factory::for(Post::class)->count(3)->create(['user_id' => $user->id]);
});
}
// Usage
$user = Factory::for(User::class)->withPosts()->create();
Stateful Factories: Use states to define reusable configurations:
// UserFactory.php
public function admin()
{
return $this->state([
'role' => 'admin',
'email' => 'admin@example.com',
]);
}
// Test
$admin = Factory::for(User::class)->admin()->create();
Raw Data Generation: Generate data without persisting to the database:
$userData = Factory::for(User::class)->raw();
Seeding Tests:
Use factories in DatabaseSeeder or test-specific seeders:
public function run()
{
Factory::for(User::class)->count(10)->create();
}
Test-Driven Development (TDD):
TestDummy to generate the required data.public function test_user_can_create_post()
{
$user = Factory::for(User::class)->create();
$post = Factory::for(Post::class)->create(['user_id' => $user->id]);
// Assertions...
}
Integration Testing:
$user = Factory::for(User::class)->create();
$response = $this->actingAs($user)->post('/posts', ['title' => 'Hello']);
Data Migration Testing:
$oldUser = Factory::for(User::class)->state(['legacy_id' => 123])->create();
Leverage Laravel’s Testing Helpers:
Combine with DatabaseTransactions or RefreshDatabase traits:
use RefreshDatabase;
public function test_something()
{
$this->refreshDatabase();
$user = Factory::for(User::class)->create();
// Test...
}
Customize Factories Dynamically: Override factory attributes per test:
$user = Factory::for(User::class)
->state(['email' => 'custom@example.com'])
->create();
Use with Pest PHP: If using Pest, adapt the syntax:
$user = create(User::class, ['name' => 'John']); // Native Pest
// Or with TestDummy:
$user = Factory::for(User::class)->create(['name' => 'John']);
Batch Operations: Generate large datasets efficiently:
$users = Factory::for(User::class)->count(1000)->create();
Deprecated Laravel Versions:
Database Transactions:
RefreshDatabase or DatabaseTransactions can lead to shared state between tests.use DatabaseTransactions;
public function test_something()
{
$this->beginDatabaseTransaction();
// Test...
}
Overly Complex Factories:
afterCreating or has relationships can become unmaintainable.ID Conflicts:
Schema::disableForeignKeyConstraints();
DB::statement('ALTER TABLE users AUTO_INCREMENT = 1');
Missing Auto-Discovery:
Laracasts\TestDummy\TestDummyServiceProvider::class,
Inspect Raw Data:
Use raw() to debug factory output:
$data = Factory::for(User::class)->raw();
dd($data);
Factory Not Found:
Ensure the factory class exists in database/factories/ and follows Laravel’s naming conventions (*Factory.php).
Relationship Errors:
Verify afterCreating or has methods are correctly referencing model classes:
// Wrong (undefined class)
$this->afterCreating(function ($user) {
Factory::for(Post::class)->create(['user_id' => $user->id]);
});
// Right (imported or fully qualified)
use App\Models\Post;
CI Database Issues:
SQLite paths may cause failures in CI. Configure .env.testing:
DB_CONNECTION=sqlite
DB_DATABASE=:memory:
Reuse Factories Across Tests:
Define factories in database/factories/ and reuse them in all test suites.
Combine with Faker: Use Faker’s methods directly in factories:
public function definition()
{
return [
'name' => $this->faker->name,
'email' => $this->faker->unique()->safeEmail,
];
}
Test Data Consistency:
Use state() to enforce consistent test data:
$user = Factory::for(User::class)
->state(['verified' => true])
->create();
Performance Optimization:
$users = Factory::for(User::class)->times(1000)->create();
$this->withoutExceptionHandling();
$this->afterApplicationCreated(function () {
DB::rollBack();
});
Extend Native Factories: Hybrid approach with Laravel’s built-in factories:
$user = User::factory()->create(); // Native
// Or with TestDummy:
$user = Factory::for(User::class)->create();
Document Factory Usage: Add comments in factories to explain states/relationships:
/**
* Creates an admin user with 5 posts.
*/
public function adminWithPosts()
{
return $this->admin()->withPosts();
}
Avoid Hardcoding: Use environment variables or config for dynamic factory data:
public function definition()
{
return [
'email' => config('testing.default_email'),
];
}
Test Factory Behavior: Write tests for factories themselves to ensure data consistency:
public function test_user_factory_has_email()
{
$user = Factory::for(User::class)->create();
$this->assertEmailIsValid($user->email);
}
Legacy Code Workarounds: For older Laravel versions, manually register the package:
use Laracasts\TestDummy\TestDummy;
TestDummy::register();
Alternative: Use Pest:
If adopting Pest PHP, consider its built-in create() helper, which may reduce dependency on testdummy:
How can I help you explore Laravel packages today?