Generate PHP class instances populated with dummy data using Faker
- PHP >= 8.0
You can install the package via composer:
composer require directorytree/dummy
Consider you have a class representing a restaurant reservation:
namespace App\Data;
class Reservation
{
/**
* Create a new reservation instance.
*/
public function __construct(
public string $name,
public string $email,
public DateTime $date,
) {}
}
To make dummy instances of this class during testing, you have to manually populate it with dummy data.
This can quickly get out of hand as your class grows, and you may find yourself writing the same dummy data generation code over and over again.
Dummy provides you with a simple way to generate dummy instances of your classes using a simple API:
// Generate one instance:
$reservation = Reservation::factory()->make();
// Generate multiple instances:
$collection = Reservation::factory()->count(5)->make();
Dummy provides you two different ways to generate classes with dummy data.
The HasFactory
trait is applied directly to the class you would like to generate dummy instances of.
To use the HasFactory
trait, you must implement the toFactoryInstance
and getFactoryDefinition
methods:
Note
The HasFactory
trait does not provide you the capability of defining state methods or callbacks.
If you need this functionality, you should define a separate Factory
class instead.
namespace App\Data;
use DateTime;
use Faker\Generator;
use DirectoryTree\Dummy\HasFactory;
class Reservation
{
use HasFactory;
/**
* Create a new reservation instance.
*/
public function __construct(
public string $name,
public string $email,
public DateTime $date,
) {}
/**
* Define the factory's default state.
*/
protected function getFactoryDefinition(Generator $faker): array
{
return [
'name' => $faker->name(),
'email' => $faker->email(),
'datetime' => $faker->dateTime(),
];
}
/**
* Create a new instance of the class using the factory definition.
*/
protected static function toFactoryInstance(array $attributes): static
{
return new static(
$attributes['name'],
$attributes['email'],
$attributes['datetime'],
);
}
}
Once implemented, you may call the Reservation::factory()
method to create a new dummy factory:
$factory = Reservation::factory();
If you need more control over the dummy data generation process, you may use the Factory
class.
The Factory
class is used to generate dummy instances of a class using a separate factory class definition.
To use the Factory
class, you must extend it with your own and override the definition
and generate
methods:
namespace App\Factories;
use App\Data\Reservation;
use DirectoryTree\Dummy\Factory;
class ReservationFactory extends Factory
{
/**
* Define the factory's default state.
*/
protected function definition(): array
{
return [
'name' => $this->faker->name(),
'email' => $this->faker->email(),
'datetime' => $this->faker->dateTime(),
];
}
/**
* Generate a new instance of the class.
*/
protected function generate(array $attributes): Reservation
{
return new Reservation(
$attributes['name'],
$attributes['email'],
$attributes['datetime'],
);
}
}
Once you've defined a factory, you can generate dummy instances of your class using the make
method:
// Using the trait:
$reservation = Reservation::factory()->make();
// Using the factory class:
$reservation = ReservationFactory::new()->make();
To add or override attributes in your definition, you may pass an array of attributes to the make
method:
$reservation = Reservation::factory()->make([
'name' => 'John Doe',
]);
To generate multiple instances of the class, you may use the count
method:
This will return a
Illuminate\SupportCollection
instance containing the generated classes.
$collection = Reservation::factory()->count(5)->make();
State manipulation methods allow you to define discrete modifications that can be applied to your dummy factories in any combination.
For example, your App\Factories\Reservation
factory might contain a tomorrow
state method that modifies one of its default attribute values:
class ReservationFactory extends Factory
{
// ...
/**
* Indicate that the reservation is for tomorrow.
*/
public function tomorrow(): Factory
{
return $this->state(function (array $attributes) {
return ['datetime' => new DateTime('tomorrow')];
});
}
}
Factory callbacks are registered using the afterMaking
method and allow you to perform
additional tasks after making or creating a class. You should register these callbacks
by defining a configure
method on your factory class. This method will be
automatically called when the factory is instantiated:
class ReservationFactory extends Factory
{
// ...
/**
* Configure the dummy factory.
*/
protected function configure(): static
{
return $this->afterMaking(function (Reservation $reservation) {
// ...
});
}
}
Sometimes you may wish to alternate the value of a given attribute for each generated class.
You may accomplish this by defining a state transformation as a sequence
:
Reservation::factory()
->count(3)
->sequence(
['datetime' => new Datetime('tomorrow')],
['datetime' => new Datetime('next week')],
['datetime' => new Datetime('next month')],
)
->make();
By default, when making more than one dummy class, an instance of Illuminate\Support\Collection
will be returned.
If you need to customize the collection of classes generated by a factory, you may override the collect
method:
class ReservationFactory extends Factory
{
// ...
/**
* Create a new collection of classes.
*/
public function collect(array $instances = []): ReservationCollection
{
return new ReservationCollection($instances);
}
}