主题
数据库测试
简介
Laravel 提供了各种有用的工具和断言,使测试数据库驱动的应用变得更加容易。此外,Laravel 模型工厂和 seeder 使得使用应用的 Eloquent 模型和关联来创建测试数据库记录变得轻而易举。我们将在以下文档中讨论所有这些强大的功能。
每次测试后重置数据库
在进一步讨论之前,让我们先讨论如何在每次测试后重置数据库,以便前一个测试的数据不会干扰后续测试。Laravel 自带的 Illuminate\Foundation\Testing\RefreshDatabase trait 会为你处理这个问题。只需在测试类中使用该 trait:
php
<?php
use Illuminate\Foundation\Testing\RefreshDatabase;
pest()->use(RefreshDatabase::class);
test('basic example', function () {
$response = $this->get('/');
// ...
});php
<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class ExampleTest extends TestCase
{
use RefreshDatabase;
/**
* 一个基本的功能测试示例。
*/
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 模型定义一组默认属性,而不是在创建测试数据时手动指定每一列的值。
要了解更多关于创建和使用模型工厂来创建模型的信息,请参阅完整的模型工厂文档。定义模型工厂后,你可以在测试中使用工厂来创建模型:
php
use App\Models\User;
test('models can be instantiated', function () {
$user = User::factory()->create();
// ...
});php
use App\Models\User;
public function test_models_can_be_instantiated(): void
{
$user = User::factory()->create();
// ...
}运行 Seeder
如果你想在功能测试期间使用数据库 seeder 来填充数据库,可以调用 seed 方法。默认情况下,seed 方法将执行 DatabaseSeeder,它应该执行你所有的其他 seeder。或者,你可以将特定的 seeder 类名传递给 seed 方法:
php
<?php
use Database\Seeders\OrderStatusSeeder;
use Database\Seeders\TransactionStatusSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
pest()->use(RefreshDatabase::class);
test('orders can be created', function () {
// 运行 DatabaseSeeder...
$this->seed();
// 运行特定的 seeder...
$this->seed(OrderStatusSeeder::class);
// ...
// 运行一组特定的 seeder...
$this->seed([
OrderStatusSeeder::class,
TransactionStatusSeeder::class,
// ...
]);
});php
<?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;
/**
* 测试创建新订单。
*/
public function test_orders_can_be_created(): void
{
// 运行 DatabaseSeeder...
$this->seed();
// 运行特定的 seeder...
$this->seed(OrderStatusSeeder::class);
// ...
// 运行一组特定的 seeder...
$this->seed([
OrderStatusSeeder::class,
TransactionStatusSeeder::class,
// ...
]);
}
}或者,你可以指示 Laravel 在使用 RefreshDatabase trait 的每个测试之前自动填充数据库。你可以通过将 Seed 属性添加到基础测试类来实现这一点:
php
<?php
namespace Tests;
use Illuminate\Foundation\Testing\Attributes\Seed;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
#[Seed]
abstract class TestCase extends BaseTestCase
{
}当存在 Seed 属性时,测试将在使用 RefreshDatabase trait 的每个测试之前运行 Database\Seeders\DatabaseSeeder 类。但是,你可以通过在测试类上使用 Seeder 属性来指定应执行的特定 seeder:
php
<?php
namespace Tests\Feature;
use Database\Seeders\OrderStatusSeeder;
use Illuminate\Foundation\Testing\Attributes\Seeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
#[Seeder(OrderStatusSeeder::class)]
class OrderTest extends TestCase
{
use RefreshDatabase;
// ...
}可用的断言
Laravel 为你的 Pest 或 PHPUnit 功能测试提供了多个数据库断言。我们将在下面讨论每个断言。
assertDatabaseCount
断言数据库中的某个表包含给定数量的记录:
php
$this->assertDatabaseCount('users', 5);assertDatabaseEmpty
断言数据库中的某个表不包含任何记录:
php
$this->assertDatabaseEmpty('users');assertDatabaseHas
断言数据库中的某个表包含匹配给定键/值查询约束的记录:
php
$this->assertDatabaseHas('users', [
'email' => 'sally@example.com',
]);assertDatabaseMissing
断言数据库中的某个表不包含匹配给定键/值查询约束的记录:
php
$this->assertDatabaseMissing('users', [
'email' => 'sally@example.com',
]);assertSoftDeleted
assertSoftDeleted 方法可用于断言给定的 Eloquent 模型已被"软删除":
php
$this->assertSoftDeleted($user);assertNotSoftDeleted
assertNotSoftDeleted 方法可用于断言给定的 Eloquent 模型未被"软删除":
php
$this->assertNotSoftDeleted($user);assertModelExists
断言给定的模型或模型集合存在于数据库中:
php
use App\Models\User;
$user = User::factory()->create();
$this->assertModelExists($user);assertModelMissing
断言给定的模型或模型集合不存在于数据库中:
php
use App\Models\User;
$user = User::factory()->create();
$user->delete();
$this->assertModelMissing($user);expectsDatabaseQueryCount
expectsDatabaseQueryCount 方法可在测试开始时调用,以指定你期望在测试期间运行的数据库查询总数。如果实际执行的查询数量与此期望不完全匹配,测试将失败:
php
$this->expectsDatabaseQueryCount(5);
// Test...