Database testing
- Reset the database after each test
- Create model factory
- Factory status
- Factory callback
- Use model factory
- Override properties
- Persistence Model
- Available assertion methods
- Introduction
- Generate model factory
- Restart after each test Set database
- Writing factory
- Use model factory in tests
- Available assertion methods
Database Testing
Introduction
Laravel provides a variety of useful tools to make testing database-driven applications easier. First, you can use the assertDatabaseHas
helper to assert that data present in the database matches a given set of conditions. For example, if you want to verify that a record in the users
table has the email
value for sally @ example.com
, you would do the following:
public function testDatabase(){ // Make call to application... $this->assertDatabaseHas('users', [ 'email' => 'sally@example.com' ]); }
You can also use the assertDatabaseMissing
helper to assert that data does not exist in the database. The
assertDatabaseHas
method and other similar helpers are provided for convenience. You are free to use any of PHPUnit's built-in assertion methods to supplement your tests.
Generate model factory
Use make:factory
Artisan command to create a model factory:
php artisan make:factory PostFactory
The location of the newly generated factory is in the database/factories
directory. The
--model
option can be used to indicate the name of the model created by the factory. This option will pre-populate the generated factory file with the given model:
php artisan make:factory PostFactory --model=Post
Reset the database after each test
After each test It is often useful to reset the database afterwards so that data from a previous test does not interfere with subsequent tests. RefreshDatabase
feature takes the most optimized approach to migrating test databases, depending on whether you are using an in-memory or traditional database. Use traits on your test class and everything will be taken care of for you:
<?php namespace Tests\Feature; use Tests\TestCase; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Foundation\Testing\WithoutMiddleware; class ExampleTest extends TestCase{ use RefreshDatabase; /** * 一个基本功能测试示例 * * @return void */ public function testBasicExample() { $response = $this->get('/'); // ... } }
Create Model Factory
When testing, you may need to Insert a few records into the database before testing. When creating this test data, instead of manually specifying the values for each column, Laravel allows you to use a model factory to define a set of default properties for each Eloquent model. Before you start testing, take a look at the database/factories/UserFactory.php
file in your application. Out of the box, this file contains a factory definition:
use Illuminate\Support\Str; use Faker\Generator as Faker; $factory->define(App\User::class, function (Faker $faker) { return [ 'name' => $faker->name, 'email' => $faker->unique()->safeEmail, 'email_verified_at' => now(), 'password' => 'y$TKh8H1.PfQx37YgCzwiKb.KjNyWgaHb9cbcoQgdIVFlYg7B77UdFm', // secret 'remember_token' => Str::random(10), ]; });
In a Closure used as a factory definition, you can return default test values for all properties on the model. Closure will receive an instance of the Faker PHP library, which allows you to conveniently generate a variety of random data for testing.
You can also create additional factory files for each model for better organization. For example, you can create the UserFactory.php
and CommentFactory.php
files in the database/factories
directory. All files in the factories
directory will be automatically loaded by Laravel.
You can set Faker's locale by adding the
faker_locale
option in theconfig/app.php
configuration file.
Factory States
States allow you to define discrete modifications that can be applied to a model factory in any combination. For example, your User
model might have a deinquent
state where one of its default property values can be modified. You can define state transitions using the state
method. For simple states, you can pass a set of property modifications:
$factory->state(App\User::class, 'delinquent', [ 'account_status' => 'delinquent', ]);
If your state requires calculations or $ faker
instances, you can use Closure to calculate the state's property modifications:
$factory->state(App\User::class, 'address', function ($faker) { return [ 'address' => $faker->address, ]; });
Factory callback
Use the afterMaking
and afterCreating
methods to register a factory callback and allow you to Or perform other tasks after creating the model. For example, you can use callbacks to associate other models with the created model:
$factory->afterMaking(App\User::class, function ($user, $faker) { // ... }); $factory->afterCreating(App\User::class, function ($user, $faker) { $user->accounts()->save(factory(App\Account::class)->make()); });
You can also define callbacks for factory states:
$factory->afterMakingState(App\User::class, 'delinquent', function ($user, $faker) { // ... }); $factory->afterCreatingState(App\User::class, 'delinquent', function ($user, $faker) { // ... });
Use model factory
Create model
After the model factory is defined, you can use the global factory# in a test or seed file ## Function to generate model instances. So, let's look at some examples of creating models. First, we will use the
make method to create models without saving them to the database:
public function testDatabase(){ $user = factory(App\User::class)->make(); //在测试中使用模型... }You can also create a collection of many models or create a model of a given type:
//创建三个 App\User 实例... $users = factory(App\User::class, 3)->make();Applying StatesYou can also apply any states to a model. If you want to apply multiple state transitions to a model, you should specify the name of each state to be applied:
$users = factory(App\User::class, 5)->states('delinquent')->make(); $users = factory(App\User::class, 5)->states('premium', 'delinquent')->make();Override Properties If you want to override some of the model's default values, you can An array of values passed to the
make method. Only the specified values will be replaced, while the remaining values are still set to the factory-specified default values:
$user = factory(App\User::class)->make([ 'name' => 'Abigail', ]);Persistence Model# The ##create
method not only creates model instances, but also saves them to the database using Eloquent's save
method:
You can do this by passing an array to public function testDatabase(){
// 创建单个 App\User 实例...
$user = factory(App\User::class)->create();
// 创建3个 App\User 实例..
$users = factory(App\User::class, 3)->create();
// 在测试中使用模型...
}
Method to override properties on a model: $user = factory(App\User::class)->create([
'name' => 'Abigail',
]);
In this example, we will attach some relationships that create the model. When using the You can also attach relationships to the model using the Closure attribute in the factory definition. For example, if you wanted to create a new These closures receive a Array: PHPUnit testing:Relationships
create
method to create multiple models, an Eloquent collection instance is returned, so that convenience methods such as each can be used on the collection: $users = factory(App\User::class, 3)
->create()
->each(function ($user) {
$user->posts()->save(factory(App\Post::class)->make());
});
Association & Property Closure
User
instance when creating a Post
, you would 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;
}
];
});
$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;
}
];
});
##Available assertion methodsLaravel provides multiple database assertion methods for
Description | |
---|---|
Assert that the database table contains the given data. | |
Assert that the database table does not contain the given data. | |
Assert that the specified record in the database has been soft deleted. |