Skip to content

Commit d62f263

Browse files
authored
Merge pull request #188 from josepostiga/fix/database-model-factories
[8.x] Fix model factories documentation section
2 parents a55fdd6 + b26506e commit d62f263

File tree

1 file changed

+89
-67
lines changed

1 file changed

+89
-67
lines changed

testing.md

Lines changed: 89 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -198,93 +198,115 @@ Another option is to wrap every test case in a database transaction. Again, Lume
198198
<a name="model-factories"></a>
199199
### Model Factories
200200

201-
When testing, it is common to need to insert a few records into your database before executing your test. Instead of manually specifying the value of each column when you create this test data, Lumen allows you to define a default set of attributes for each of your [Eloquent models](https://laravel.com/docs/eloquent) using "factories". To get started, take a look at the `database/factories/ModelFactory.php` file in your application. Out of the box, this file contains one factory definition:
201+
When testing, it is common to need to insert a few records into your database before executing your test. Instead of manually specifying the value of each column when you create this test data, Lumen allows you to define a default set of attributes for each of your [Eloquent models](https://laravel.com/docs/eloquent) using model factories.
202202

203-
$factory->define('App\User', function ($faker) {
204-
return [
205-
'name' => $faker->name,
206-
'email' => $faker->email,
207-
];
208-
});
203+
To get started, take a look at the `database/factories/UserFactory.php` file in your application. Out of the box, this file contains the following factory definition:
209204

210-
Within the Closure, which serves as the factory definition, you may return the default test values of all attributes on the model. The Closure will receive an instance of the [Faker](https://github.com/fzaninotto/Faker) PHP library, which allows you to conveniently generate various kinds of random data for testing.
211-
212-
Of course, you are free to add your own additional factories to the `ModelFactory.php` file.
213-
214-
#### Multiple Factory Types
215-
216-
Sometimes you may wish to have multiple factories for the same Eloquent model class. For example, perhaps you would like to have a factory for "Administrator" users in addition to normal users. You may define these factories using the `defineAs` method:
217-
218-
$factory->defineAs('App\User', 'admin', function ($faker) {
219-
return [
220-
'name' => $faker->name,
221-
'email' => $faker->email,
222-
'admin' => true,
223-
];
224-
});
225-
226-
Instead of duplicating all of the attributes from your base user factory, you may use the `raw` method to retrieve the base attributes. Once you have the attributes, simply supplement them with any additional values you require:
205+
<?php
206+
207+
namespace Database\Factories;
208+
209+
use App\Models\User;
210+
use Illuminate\Database\Eloquent\Factories\Factory;
211+
212+
class UserFactory extends Factory
213+
{
214+
/**
215+
* The name of the factory's corresponding model.
216+
*
217+
* @var string
218+
*/
219+
protected $model = User::class;
220+
221+
/**
222+
* Define the model's default state.
223+
*
224+
* @return array
225+
*/
226+
public function definition()
227+
{
228+
return [
229+
'name' => $this->faker->name,
230+
'email' => $this->faker->unique()->safeEmail,
231+
];
232+
}
233+
}
227234

228-
$factory->defineAs('App\User', 'admin', function ($faker) use ($factory) {
229-
$user = $factory->raw('App\User');
235+
As you can see, in their most basic form, factories are classes that extend Lumen's base factory class and define a `model` property and `definition` method. The `definition` method returns the default set of attribute values that should be applied when creating a model using the factory.
230236

231-
return array_merge($user, ['admin' => true]);
232-
});
237+
Via the `faker` property, factories have access to the [Faker](https://github.com/fzaninotto/Faker) PHP library, which allows you to conveniently generate various kinds of random data for testing.
233238

234-
#### Using Factories In Tests
239+
#### Factory States
235240

236-
Once you have defined your factories, you may use them in your tests or database seed files to generate model instances using the global `factory` function. So, let's take a look at a few examples of creating models. First, we'll use the `make` method, which creates models but does not save them to the database:
241+
State manipulation methods allow you to define discrete modifications that can be applied to your model factories in any combination. For example, your `User` model might have a `suspended` state that modifies one of its default attribute values. You may define your state transformations using the base factory's `state` method. You may name your state method anything you like. After all, it's just a typical PHP method:
237242

238-
public function testDatabase()
243+
/**
244+
* Indicate that the user is suspended.
245+
*
246+
* @return \Illuminate\Database\Eloquent\Factories\Factory
247+
*/
248+
public function suspended()
239249
{
240-
$user = factory('App\User')->make();
241-
242-
// Use model in tests...
250+
return $this->state([
251+
'account_status' => 'suspended',
252+
]);
243253
}
244254

245-
If you would like to override some of the default values of your models, you may pass an array of values to the `make` method. Only the specified values will be replaced while the rest of the values remain set to their default values as specified by the factory:
255+
If your state transformation requires access to the other attributes defined by the factory, you may pass a callback to the `state` method. The callback will receive the array of raw attributes defined for the factory:
246256

247-
$user = factory('App\User')->make([
248-
'name' => 'Abigail',
249-
]);
250-
251-
You may also create a Collection of many models or create models of a given type:
252-
253-
// Create three App\User instances...
254-
$users = factory('App\User', 3)->make();
257+
/**
258+
* Indicate that the user is suspended.
259+
*
260+
* @return \Illuminate\Database\Eloquent\Factories\Factory
261+
*/
262+
public function suspended()
263+
{
264+
return $this->state(function (array $attributes) {
265+
return [
266+
'account_status' => 'suspended',
267+
];
268+
});
269+
}
255270

256-
// Create an App\User "admin" instance...
257-
$user = factory('App\User', 'admin')->make();
271+
#### Factory Callbacks
258272

259-
// Create three App\User "admin" instances...
260-
$users = factory('App\User', 'admin', 3)->make();
273+
Factory callbacks are registered using the `afterMaking` and `afterCreating` methods and allow you to perform additional tasks after making or creating a model. You should register these callbacks by defining a `configure` method on the factory class. This method will automatically be called by Laravel when the factory is instantiated:
261274

262-
#### Persisting Factory Models
275+
namespace Database\Factories;
263276

264-
The `create` method not only creates the model instances, but also saves them to the database using Eloquent's `save` method:
277+
use App\Models\User;
278+
use Illuminate\Database\Eloquent\Factories\Factory;
279+
use Illuminate\Support\Str;
265280

266-
public function testDatabase()
281+
class UserFactory extends Factory
267282
{
268-
$user = factory('App\User')->create();
269-
270-
// Use model in tests...
283+
/**
284+
* The name of the factory's corresponding model.
285+
*
286+
* @var string
287+
*/
288+
protected $model = User::class;
289+
290+
/**
291+
* Configure the model factory.
292+
*
293+
* @return $this
294+
*/
295+
public function configure()
296+
{
297+
return $this->afterMaking(function (User $user) {
298+
//
299+
})->afterCreating(function (User $user) {
300+
//
301+
});
302+
}
303+
304+
// ...
271305
}
272306

273-
Again, you may override attributes on the model by passing an array to the `create` method:
274-
275-
$user = factory('App\User')->create([
276-
'name' => 'Abigail',
277-
]);
278-
279-
#### Adding Relations To Models
280-
281-
You may even persist multiple models to the database. In this example, we'll even attach a relation to the created models. When using the `create` method to create multiple models, an Eloquent [collection instance](http://laravel.com/docs/eloquent-collections) is returned, allowing you to use any of the convenient functions provided by the collection, such as `each`:
307+
#### Using Factories In Tests
282308

283-
$users = factory('App\User', 3)
284-
->create()
285-
->each(function($u) {
286-
$u->posts()->save(factory('App\Post')->make());
287-
});
309+
The Lumen model factories based on the same code as the Laravel model factories. Therefore, please consult the [full Laravel documentation](https://laravel.com/docs/8.x/database-testing#using-factories) for usage examples.
288310

289311
<a name="mocking"></a>
290312
## Mocking

0 commit comments

Comments
 (0)