跳至内容

数据库测试

介绍

Laravel 提供了各种实用的工具和断言,让您可以更轻松地测试数据库驱动的应用程序。此外,Laravel 的模型Factories和种子器让您可以轻松地使用应用程序的 Eloquent 模型和关系创建测试数据库记录。我们将在后续文档中讨论所有这些强大的功能。

每次测试后重置数据库

在进一步讨论之前,我们先讨论一下如何在每次测试后重置数据库,这样前一次测试的数据就不会干扰后续测试。Laravel 内置的Illuminate\Foundation\Testing\RefreshDatabasetrait 会帮你解决这个问题。只需在测试类中使用该 trait 即可:

1<?php
2 
3use Illuminate\Foundation\Testing\RefreshDatabase;
4 
5uses(RefreshDatabase::class);
6 
7test('basic example', function () {
8 $response = $this->get('/');
9 
10 // ...
11});
1<?php
2 
3namespace Tests\Feature;
4 
5use Illuminate\Foundation\Testing\RefreshDatabase;
6use Tests\TestCase;
7 
8class ExampleTest extends TestCase
9{
10 use RefreshDatabase;
11 
12 /**
13 * A basic functional test example.
14 */
15 public function test_basic_example(): void
16 {
17 $response = $this->get('/');
18 
19 // ...
20 }
21}

如果您的数据库架构是最新的,此Illuminate\Foundation\Testing\RefreshDatabase特性不会迁移您的数据库。相反,它只会在数据库事务中执行测试。因此,任何由未使用此特性的测试用例添加到数据库的记录可能仍会存在于数据库中。

如果您想完全重置数据库,可以使用Illuminate\Foundation\Testing\DatabaseMigrationsIlluminate\Foundation\Testing\DatabaseTruncationtrait。但是,这两个选项都比RefreshDatabasetrait 慢得多。

模型Factories

测试时,您可能需要在执行测试之前向数据库中插入一些记录。Laravel 允许您使用模型Factories为每个Eloquent 模型定义一组默认属性,而无需在创建测试数据时手动指定每列的值。

要了解有关创建和使用模型Factories创建模型的更多信息,请参阅完整的模型Factories文档。定义模型Factories后,您可以在测试中使用该Factories来创建模型:

1use App\Models\User;
2 
3test('models can be instantiated', function () {
4 $user = User::factory()->create();
5 
6 // ...
7});
1use App\Models\User;
2 
3public function test_models_can_be_instantiated(): void
4{
5 $user = User::factory()->create();
6 
7 // ...
8}

运行Seeding机

如果您想在功能测试期间使用数据库种子填充数据库,可以调用seed方法。默认情况下,该seed方法将执行DatabaseSeeder,这将执行所有其他种子。或者,您可以将特定的种子类名传递给该seed方法:

1<?php
2 
3use Database\Seeders\OrderStatusSeeder;
4use Database\Seeders\TransactionStatusSeeder;
5use Illuminate\Foundation\Testing\RefreshDatabase;
6 
7uses(RefreshDatabase::class);
8 
9test('orders can be created', function () {
10 // Run the DatabaseSeeder...
11 $this->seed();
12 
13 // Run a specific seeder...
14 $this->seed(OrderStatusSeeder::class);
15 
16 // ...
17 
18 // Run an array of specific seeders...
19 $this->seed([
20 OrderStatusSeeder::class,
21 TransactionStatusSeeder::class,
22 // ...
23 ]);
24});
1<?php
2 
3namespace Tests\Feature;
4 
5use Database\Seeders\OrderStatusSeeder;
6use Database\Seeders\TransactionStatusSeeder;
7use Illuminate\Foundation\Testing\RefreshDatabase;
8use Tests\TestCase;
9 
10class ExampleTest extends TestCase
11{
12 use RefreshDatabase;
13 
14 /**
15 * Test creating a new order.
16 */
17 public function test_orders_can_be_created(): void
18 {
19 // Run the DatabaseSeeder...
20 $this->seed();
21 
22 // Run a specific seeder...
23 $this->seed(OrderStatusSeeder::class);
24 
25 // ...
26 
27 // Run an array of specific seeders...
28 $this->seed([
29 OrderStatusSeeder::class,
30 TransactionStatusSeeder::class,
31 // ...
32 ]);
33 }
34}

或者,你可以让 Laravel 在每个使用该特征的测试之前自动填充数据库。你可以在测试基类上RefreshDatabase定义一个属性来实现这一点:$seed

1<?php
2 
3namespace Tests;
4 
5use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
6 
7abstract class TestCase extends BaseTestCase
8{
9 /**
10 * Indicates whether the default seeder should run before each test.
11 *
12 * @var bool
13 */
14 protected $seed = true;
15}

$seed属性为时true,测试将Database\Seeders\DatabaseSeeder在每个使用该特征的测试之前运行该类。但是,您可以通过在测试类上RefreshDatabase定义一个属性来指定要执行的特定种子程序:$seeder

1use Database\Seeders\OrderStatusSeeder;
2 
3/**
4 * Run a specific seeder before each test.
5 *
6 * @var string
7 */
8protected $seeder = OrderStatusSeeder::class;

可用的断言

Laravel 为PestPHPUnit功能测试提供了多种数据库断言。我​​们将在下文逐一讨论这些断言。

断言数据库计数

断言数据库中的表包含给定数量的记录:

1$this->assertDatabaseCount('users', 5);

断言数据库空

断言数据库中的表不包含任何记录:

1$this->assertDatabaseEmpty('users');

断言数据库有

断言数据库中的表包含与给定的键/值查询约束匹配的记录:

1$this->assertDatabaseHas('users', [
2 'email' => 'sally@example.com',
3]);

断言数据库缺失

断言数据库中的表不包含与给定的键/值查询约束匹配的记录:

1$this->assertDatabaseMissing('users', [
2 'email' => 'sally@example.com',
3]);

断言软删除

assertSoftDeleted方法可用于断言给定的 Eloquent 模型已被“软删除”:

1$this->assertSoftDeleted($user);

断言非软删除

assertNotSoftDeleted方法可用于断言给定的 Eloquent 模型尚未被“软删除”:

1$this->assertNotSoftDeleted($user);

assertModelExists

断言数据库中存在给定的模型:

1use App\Models\User;
2 
3$user = User::factory()->create();
4 
5$this->assertModelExists($user);

断言模型缺失

断言数据库中不存在给定的模型:

1use App\Models\User;
2 
3$user = User::factory()->create();
4 
5$user->delete();
6 
7$this->assertModelMissing($user);

预期数据库查询计数

expectsDatabaseQueryCount方法可以在测试开始时调用,以指定测试期间预计运行的数据库查询总数。如果实际执行的查询数量与预期不完全匹配,则测试将失败:

1$this->expectsDatabaseQueryCount(5);
2 
3// Test...