数据库测试
简介
Laravel 提供了各种有用的工具和断言,使测试你的数据库驱动应用程序更加容易。此外,Laravel 模型工厂和填充器使使用你的应用程序的 Eloquent 模型和关系创建测试数据库记录变得轻松。我们将在以下文档中讨论所有这些强大的功能。
每次测试后重置数据库
在深入讨论之前,让我们讨论如何在每次测试后重置你的数据库,以便先前测试的数据不会干扰后续测试。Laravel 包含的 Illuminate\Foundation\Testing\RefreshDatabase
trait 将为你处理此问题。只需在你的测试类中使用该 trait 即可
<?php use Illuminate\Foundation\Testing\RefreshDatabase; uses(RefreshDatabase::class); test('basic example', function () { $response = $this->get('/'); // ...});
<?php namespace Tests\Feature; use Illuminate\Foundation\Testing\RefreshDatabase;use Tests\TestCase; class ExampleTest extends TestCase{ use RefreshDatabase; /** * A basic functional test example. */ public function test_basic_example(): void { $response = $this->get('/'); // ... }}
如果你的架构是最新的,Illuminate\Foundation\Testing\RefreshDatabase
trait 不会迁移你的数据库。相反,它只会在一个数据库事务中执行测试。因此,不使用此 trait 的测试用例添加到数据库中的任何记录可能仍然存在于数据库中。
如果你想完全重置数据库,你可以使用 Illuminate\Foundation\Testing\DatabaseMigrations
或 Illuminate\Foundation\Testing\DatabaseTruncation
trait 代替。但是,这两个选项都比 RefreshDatabase
trait 慢得多。
模型工厂
在测试时,你可能需要在执行测试之前将一些记录插入到数据库中。Laravel 允许你使用 模型工厂为每个 Eloquent 模型定义一组默认属性,而不是在创建此测试数据时手动指定每个列的值。
要了解有关创建和利用模型工厂来创建模型的更多信息,请查阅完整的 模型工厂文档。定义模型工厂后,你可以在测试中使用该工厂来创建模型
use App\Models\User; test('models can be instantiated', function () { $user = User::factory()->create(); // ...});
use App\Models\User; public function test_models_can_be_instantiated(): void{ $user = User::factory()->create(); // ...}
运行填充器
如果你想在功能测试期间使用 数据库填充器填充你的数据库,你可以调用 seed
方法。默认情况下,seed
方法将执行 DatabaseSeeder
,该 seeder 应执行你的所有其他填充器。或者,你可以将特定的填充器类名传递给 seed
方法
<?php use Database\Seeders\OrderStatusSeeder;use Database\Seeders\TransactionStatusSeeder;use Illuminate\Foundation\Testing\RefreshDatabase; uses(RefreshDatabase::class); test('orders can be created', function () { // Run the DatabaseSeeder... $this->seed(); // Run a specific seeder... $this->seed(OrderStatusSeeder::class); // ... // Run an array of specific seeders... $this->seed([ OrderStatusSeeder::class, TransactionStatusSeeder::class, // ... ]);});
<?php namespace Tests\Feature; use Database\Seeders\OrderStatusSeeder;use Database\Seeders\TransactionStatusSeeder;use Illuminate\Foundation\Testing\RefreshDatabase;use Tests\TestCase; class ExampleTest extends TestCase{ use RefreshDatabase; /** * Test creating a new order. */ public function test_orders_can_be_created(): void { // Run the DatabaseSeeder... $this->seed(); // Run a specific seeder... $this->seed(OrderStatusSeeder::class); // ... // Run an array of specific seeders... $this->seed([ OrderStatusSeeder::class, TransactionStatusSeeder::class, // ... ]); }}
或者,你可以指示 Laravel 在每次使用 RefreshDatabase
trait 的测试之前自动填充数据库。你可以在你的基本测试类上定义一个 $seed
属性来实现此目的
<?php namespace Tests; use Illuminate\Foundation\Testing\TestCase as BaseTestCase; abstract class TestCase extends BaseTestCase{ /** * Indicates whether the default seeder should run before each test. * * @var bool */ protected $seed = true;}
当 $seed
属性为 true
时,测试将在每次使用 RefreshDatabase
trait 的测试之前运行 Database\Seeders\DatabaseSeeder
类。但是,你可以通过在你的测试类上定义一个 $seeder
属性来指定应执行的特定填充器
use Database\Seeders\OrderStatusSeeder; /** * Run a specific seeder before each test. * * @var string */protected $seeder = OrderStatusSeeder::class;
可用断言
Laravel 为你的 Pest 或 PHPUnit 功能测试提供了几个数据库断言。我们将在下面讨论这些断言中的每一个。
assertDatabaseCount
断言数据库中的表包含给定数量的记录
$this->assertDatabaseCount('users', 5);
assertDatabaseEmpty
断言数据库中的表不包含任何记录
$this->assertDatabaseEmpty('users');
assertDatabaseHas
断言数据库中的表包含与给定的键/值查询约束匹配的记录
$this->assertDatabaseHas('users', []);
assertDatabaseMissing
断言数据库中的表不包含与给定的键/值查询约束匹配的记录
$this->assertDatabaseMissing('users', []);
assertSoftDeleted
assertSoftDeleted
方法可用于断言给定的 Eloquent 模型已被“软删除”
$this->assertSoftDeleted($user);
assertNotSoftDeleted
assertNotSoftDeleted
方法可用于断言给定的 Eloquent 模型尚未被“软删除”
$this->assertNotSoftDeleted($user);
assertModelExists
断言给定的模型存在于数据库中
use App\Models\User; $user = User::factory()->create(); $this->assertModelExists($user);
assertModelMissing
断言给定的模型不存在于数据库中
use App\Models\User; $user = User::factory()->create(); $user->delete(); $this->assertModelMissing($user);
expectsDatabaseQueryCount
可以在测试开始时调用 expectsDatabaseQueryCount
方法,以指定你希望在测试期间运行的数据库查询总数。如果实际执行的查询数量与此预期不完全匹配,则测试将失败
$this->expectsDatabaseQueryCount(5); // Test...