Database testing: model factory generation and use
brief introduction
Laravel provides several useful tools to make testing database driven applications easier. First, you can use auxiliary functions assertDatabaseHas
To assert whether the data in the database matches the given data set. For example, if you want to pass email
Value is xueyuanjun@laravelacademy.org
Condition to data table users
To query whether the record exists, we can do the following:
public function testDatabase() { // Make call to application... $this->assertDatabaseHas('users', [ 'email' => ' xueyuanjun@laravelacademy.org ' ]); }
You can also use assertDatabaseMissing
The helper function asserts that the data does not exist in the database.
of course, assertDatabaseHas
Methods and other similar auxiliary methods are packaged for convenience. You can also use other PHPUnit built-in assertion methods to test.
Generate model factory
Model factories can be used to quickly populate data tables. To create a model factory, you can use the Artisan Command make:factory
:
php artisan make:factory PostFactory
The newly created factory class is located in database/factories
Directory.
--model
Option can be used to indicate the model class corresponding to the model factory. This option pre fills the generated factory class with the given model name:
php artisan make:factory PostFactory --model=Post
Generated PostFactory
The contents are as follows:
<? php use Faker\Generator as Faker; $factory->define(App\Post::class, function (Faker $faker) { return [ // ]; });
Reset database after each test
It is often useful to reset the database after each test, so that the data from the last test will not affect the next test. RefreshDatabase
The trait is based on whether you use an in memory database or a relational database to migrate the test database in the best way. When you use this trait on the test class, you don't need to worry about anything. The system will automatically help you reset the database after each test:
<? php namespace Tests\Feature; use Tests\TestCase; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Foundation\Testing\WithoutMiddleware; class ExampleTest extends TestCase { use RefreshDatabase; /** * A basic functional test example. * * @return void */ public function testBasicExample() { $response = $this->get('/'); // ... } }
Preparation factory
When testing, you usually need to insert new data into the database before executing the test. When creating test data, Larravel allows you to use the model factory to Eloquent model Define a default set of attribute values instead of manually specifying values for each column. To begin, let's take a look database/factories/ModelFactory.php
File, which contains a factory definition:
use Faker\Generator as Faker; $factory->define(App\User::class, function (Faker $faker) { return [ 'name' => $faker->name, 'email' => $faker->unique()->safeEmail, 'password' => '$2y$10$TKh8H1.PfQx37YgCzwiKb. KjNyWgaHb9cbcoQgdIVFlYg7B77UdFm', // secret 'remember_token' => str_random(10), ]; });
In the closure, as the factory definition, we return the default test values of all properties on the model. This closure receives the PHP library Faker Instance, which allows you to easily generate multiple types of random data for tests.
You can also create additional factory files for each model in order to better organize and manage, for example, you can database/factories
Create under directory UserFactory.php
and CommentFactory.php
File. factories
All files in the directory will be automatically loaded by Larave.
Factory status
Status allows you to define discrete modifications that can be used in the model factory in any combination, for example, User
The model may have a delinquent
Status is used to modify a default attribute value. You can use state
Method to define state transitions. For simple states, you can pass an attribute to modify the array:
$factory->state(App\User::class, 'delinquent', [ 'account_status' => 'delinquent', ]);
If your status needs to be calculated or a $faker
Instance, you can use a closed package to calculate the property modification of the state:
$factory->state(App\User::class, 'address', function ($faker) { return [ 'address' => $faker->address, ]; });
Use factory
Create model
After the factory is defined, you can use the global factory
Methods use them to generate model instances, so let's look at some examples of creating models. First, we use make
Method, which creates the model without saving it to the database:
public function testDatabase(){ $user = factory(App\User::class)->make(); //User Model Test }
You can also create multiple model collections or create models of a given type:
//Create 3 App User instances $users = factory(App\User::class, 3)->make();
Application status
You can also apply any state to the model. If you want to apply multiple state transformations to the model, you need to specify the name of each state you want to apply:
$users = factory(App\User::class, 5)->states('deliquent')->make(); $users = factory(App\User::class, 5)->states('premium', 'deliquent')->make();
Override Attributes
If you want to override some default values in the model, you can pass array values to make
Method, only the specified values will be replaced, and the remaining values will remain the default values specified by the factory:
$user = factory(App\User::class)->make([ 'name' => 'Abigail', ]);
Persistence model
create
The method can not only create model instances, but also use Eloquent's save
Method to save them to the database:
public function testDatabase() { //Create a single App User instance $user = factory(App\User::class)->create(); //Create 3 App User instances $users = factory(App\User::class, 3)->create(); //Using models in tests }
You can pass an array to create
The method overrides the attributes on the model:
$user = factory(App\User::class)->create([ 'name' => 'Abigail', ]);
Association
In this example, we add an association to the created model, and use create
Method to create multiple models, an Eloquent will be returned Collection Instance , allowing you to use all the methods provided by the collection, such as each
:
$users = factory(App\User::class, 3) ->create() ->each(function($u) { $u->posts()->save(factory(App\Post::class)->make()); });
Association&attribute closure
You can also use the closure attribute in the factory to add associations to the model. For example, if you want to create Post
Create a new User
For instance, you can do the following:
$factory->define(App\Post::class, function ($faker) { return [ 'title' => $faker->title, 'content' => $faker->paragraph, 'user_id' => function () { return factory(App\User::class)->create()->id; } ]; });
These closures also receive an array of factory properties containing them:
$factory->define(App\Post::class, function ($faker) { return [ 'title' => $faker->title, 'content' => $faker->paragraph, 'user_id' => function () { return factory(App\User::class)->create()->id; }, 'user_type' => function (array $post) { return App\User::find($post['user_id'])->type; } ]; });
Valid Assertion Methods
Larravel is PHPUnit The test provides multiple database assertion methods: method |
describe |
---|
$this->assertDatabaseHas($table, array $data); |
Assertion data table contains given data |
$this->assertDatabaseMissing($table, array $data); |
Assertion data table does not contain the given data |
$this->assertSoftDeleted($table, array $data); |
Asserting that the given record has been soft deleted |