数据库测试
简介
Laravel 提供了各种有用的工具和断言,使测试数据库驱动的应用程序更加容易。此外,Laravel 模型工厂和填充器可以轻松地使用应用程序的 Eloquent 模型和关系创建测试数据库记录。我们将在以下文档中讨论所有这些强大的功能。
每次测试后重置数据库
在继续深入之前,让我们讨论如何在每次测试后重置数据库,以避免先前测试的数据干扰后续测试。Laravel 内置的 Illuminate\Foundation\Testing\RefreshDatabase
trait 将为您处理此问题。只需在您的测试类中使用该 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(): void16 {17 $response = $this->get('/');18 19 // ...20 }21}
Illuminate\Foundation\Testing\RefreshDatabase
trait 不会在您的数据库 schema 是最新的时候迁移数据库。相反,它只会在数据库事务中执行测试。因此,未使用此 trait 的测试用例添加到数据库的任何记录可能仍然存在于数据库中。
如果您想完全重置数据库,您可以改用 Illuminate\Foundation\Testing\DatabaseMigrations
或 Illuminate\Foundation\Testing\DatabaseTruncation
traits。但是,这两种选项都比 RefreshDatabase
trait 慢得多。
模型工厂
在测试时,您可能需要在执行测试之前向数据库中插入一些记录。Laravel 允许您为每个 Eloquent 模型 定义一组默认属性,使用 模型工厂,而不是在创建此测试数据时手动指定每一列的值。
要了解有关创建和使用模型工厂来创建模型的更多信息,请查阅完整的 模型工厂文档。定义模型工厂后,您可以在测试中使用该工厂来创建模型
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(): void4{5 $user = User::factory()->create();6 7 // ...8}
运行填充器
如果您想在功能测试期间使用 数据库填充器 来填充数据库,您可以调用 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 TestCase11{12 use RefreshDatabase;13 14 /**15 * Test creating a new order.16 */17 public function test_orders_can_be_created(): void18 {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
trait 的测试之前自动填充数据库。您可以通过在基本测试类上定义 $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 bool13 */14 protected $seed = true;15}
当 $seed
属性为 true
时,测试将在每次使用 RefreshDatabase
trait 的测试之前运行 Database\Seeders\DatabaseSeeder
类。但是,您可以通过在测试类上定义 $seeder
属性来指定应执行的特定填充器
1use Database\Seeders\OrderStatusSeeder;2 3/**4 * Run a specific seeder before each test.5 *6 * @var string7 */8protected $seeder = OrderStatusSeeder::class;
可用断言
Laravel 为您的 Pest 或 PHPUnit 功能测试提供了几个数据库断言。我们将在下面讨论每个断言。
assertDatabaseCount
断言数据库中的表包含给定数量的记录
1$this->assertDatabaseCount('users', 5);
assertDatabaseEmpty
断言数据库中的表不包含任何记录
1$this->assertDatabaseEmpty('users');
assertDatabaseHas
断言数据库中的表包含与给定键/值查询约束匹配的记录
1$this->assertDatabaseHas('users', [3]);
assertDatabaseMissing
断言数据库中的表不包含与给定键/值查询约束匹配的记录
1$this->assertDatabaseMissing('users', [3]);
assertSoftDeleted
assertSoftDeleted
方法可用于断言给定的 Eloquent 模型已被“软删除”
1$this->assertSoftDeleted($user);
assertNotSoftDeleted
assertNotSoftDeleted
方法可用于断言给定的 Eloquent 模型尚未被“软删除”
1$this->assertNotSoftDeleted($user);
assertModelExists
断言给定的模型存在于数据库中
1use App\Models\User;2 3$user = User::factory()->create();4 5$this->assertModelExists($user);
assertModelMissing
断言给定的模型不存在于数据库中
1use App\Models\User;2 3$user = User::factory()->create();4 5$user->delete();6 7$this->assertModelMissing($user);
expectsDatabaseQueryCount
可以在测试开始时调用 expectsDatabaseQueryCount
方法,以指定您期望在测试期间运行的数据库查询总数。如果实际执行的查询数量与此预期不完全匹配,则测试将失败
1$this->expectsDatabaseQueryCount(5);2 3// Test...