Laravel Factories and Seeders
Chris Read
Posted on September 4, 2023
So what are Laravel factories and how are they useful? Great question, thanks. Factories are a great way to generate test data for your Eloquent models. If you end up mashing your fingers on the keyboard to create test data, then these are for you. No more Mr hsdfgiu hsuaidg for you my friend.
Defining a factory
As ever with Laravel, there’s a handy artisan command to create your factories. Generally you will want one per Model. The default Laravel install also includes one for the User model. The artisan command is:
Laravel Love Affair is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.
php artisan make:factory DogFactory
This would be the factory for your Dog model for that dog database you’re building. This will create a factory class called DogFactory and save it in database/factories.
This is how that file will look:
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Model>
*/
class DogFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition(): array
{
return [
//
];
}
}
The definition function is where we will can define the types of data that you need.
The most useful case for factories is probably to generate test data, but you can also use them to insert rows that you know you’ll need. For example, your own admin super-user that you know you’ll want to put back in the database every time you refresh it.
Let’s say that I want my dog in the database to start off with, the class might look something like this:
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Model>
*/
class DogFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition(): array
{
return [
'name' => 'Luna',
'age' => '5',
'breed' => 'God knows, possibly all of them',
'favourite_snack' => 'all'
];
}
}
Name, age, breed and favourite_snack are my DB column names, and the data I want to add is included in the array. Great! Now lets add it to the database. I’ll assume you have created the Model file and DB table via a migration. You can cal the factory via tinker on the command line:
php artisan tinker
> App\Models\Dog::factory()->create();
= App\Models\Dog {#6615
name: "Luna",
age: "5",
breed: "God knows, possibly all of them",
favourite_snack: "all",
updated_at: "2023-09-04 21:57:30",
created_at: "2023-09-04 21:57:30",
id: 1,
}
And we have a row in our DB, hooray!
Another way to get data into your DB is via seeder classes. Seeders can be run via artisan, and can give you a set of test data. You can have different seeders if you need different data for a variety of test scenarios.
Let’s create a seeder for our Dogs Model:
php artisan make:seeder DogSeeder
This will create database/seeders/DogSeeder.php, lets take a look at it:
<?php
namespace Database\Seeders;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class DogSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
//
}
}
This time we have a single method called run, in which we will carry out the actions required to seed the database. Let’s add in the call to our Dog factory:
<?php
namespace Database\Seeders;
use App\Models\Dog;
use Illuminate\Database\Seeder;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
class DogSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
Dog::factory()->create();
}
}
Notice that I’ve also added a use statement for the Dog Model namespace at the top of the file. Now we can call our Dog factory via artisan:
db:seed --class=DogSeeder
And once again we have a new row in the DB.
Creating test data using faker
Faker is a super-useful package that helps us create test data without having to manually do it. Faker has all kinds of different formats of test data you can use - names, addresses, phone numbers, emails etc. We simply have to call the right method (formatter) from our factory class. Lets amend our factory class to use faker:
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Model>
*/
class DogFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition(): array
{
return [
'name' => fake()->firstName(),
'age' => fake()->numberBetween(1, 15),
'breed' => fake()->word(),
'favourite_snack' => fake()->word()
];
}
}
The fake() helper is available to you in the Factory class, so you just need to chain the faker method you want. I think they’re all self-explanatory, I’ve just used word for breed and snack.
There are lots of faker formatters, including community contributed extensions like food names, or car data - tho I’ve not played with any third party extensions yet, let me know if you get those working. You can check out the documentation at https://github.com/fzaninotto/Faker#table-of-contents.
Finally, let’s say we want 20 dogs in our DB to test the UI - we can accomplish that back in our seeder class:
<?php
namespace Database\Seeders;
use App\Models\Dog;
use Illuminate\Database\Seeder;
class DogSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
Dog::factory()->count(20)->create();
}
}
Give that a run from artisan:
db:seed --class=DogSeeder
And you will have 20 random pups in your DB.
I hope that’s given an insight into factories in eloquent. They are incredibly useful when writing tests too, but that’s for another day.
And maybe I will call my next dog Diamond or Thurman as faker has suggested. Heck, why not save all that bother and just name your kids using faker from now on.
Posted on September 4, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 30, 2024