数据库测试
简介
Laravel 提供多种实用工具与断言,让你更容易测试依赖数据库的应用。此外,Laravel 模型工厂与填充器可轻松使用应用的 Eloquent 模型与关联创建测试数据库记录。下文将讨论这些强大功能。
每次测试后重置数据库
在继续深入之前,我们先讨论如何在每次测试后重置数据库,以免前一次测试的数据干扰后续测试。Laravel 自带的 Illuminate\Foundation\Testing\RefreshDatabase trait 会帮你处理此事。只需在测试类上使用该 trait:
<?php
use Illuminate\Foundation\Testing\RefreshDatabase;
pest()->use(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,而后者应执行你所有其他填充器。或者,你也可以向 seed 方法传入特定填充器类名:
<?php
use Database\Seeders\OrderStatusSeeder;
use Database\Seeders\TransactionStatusSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
pest()->use(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;可用断言
assertDatabaseCount
断言数据库中的某张表包含给定数量的记录:
$this->assertDatabaseCount('users', 5);assertDatabaseEmpty
断言数据库中的某张表不包含任何记录:
$this->assertDatabaseEmpty('users');assertDatabaseHas
断言数据库中的某张表包含符合给定键 / 值查询约束的记录:
$this->assertDatabaseHas('users', [
'email' => 'sally@example.com',
]);assertDatabaseMissing
断言数据库中的某张表不包含符合给定键 / 值查询约束的记录:
$this->assertDatabaseMissing('users', [
'email' => 'sally@example.com',
]);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...