Тести бази даних · Laravel
Laravel дає набір інструментів і тверджень (assertions), які спрощують тестування застосунків, що працюють з базою даних. Фабрики моделей і сідери дозволяють без зайвого болю створювати тестові записи через Eloquent-моделі та їхні звʼязки. Нижче розглянемо всі ці можливості.
Скидання бази даних після кожного тесту
Спершу поговоримо про те, як скидати базу даних після кожного тесту, щоб дані з попереднього тесту не заважали наступним. Про це подбає трейт Illuminate\Foundation\Testing\RefreshDatabase, який входить до складу Laravel. Просто використайте його у класі тесту:
<?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;
/**
* Базовий приклад функціонального тесту.
*/
public function test_basic_example(): void
{
$response = $this->get('/');
// ...
}
}
Трейт Illuminate\Foundation\Testing\RefreshDatabase не запускає міграції, якщо схема бази вже актуальна. Натомість він виконує тест усередині транзакції. Тому записи, додані до бази тестами, які цей трейт не використовують, можуть залишитися в базі.
Якщо потрібно повністю скинути базу даних, скористайтеся трейтами Illuminate\Foundation\Testing\DatabaseMigrations або Illuminate\Foundation\Testing\DatabaseTruncation. Обидва варіанти помітно повільніші за RefreshDatabase.
Фабрики моделей
Під час тестування вам може знадобитися вставити кілька записів у базу перед виконанням тесту. Замість вручну вказувати значення кожної колонки для таких тестових даних, 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();
// ...
}
Запуск сідерів
Якщо під час feature-тесту ви хочете наповнити базу через сідери, викличте метод 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 () {
// Запустити DatabaseSeeder...
$this->seed();
// Запустити конкретний сідер...
$this->seed(OrderStatusSeeder::class);
// ...
// Запустити масив конкретних сідерів...
$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;
/**
* Тест створення нового замовлення.
*/
public function test_orders_can_be_created(): void
{
// Запустити DatabaseSeeder...
$this->seed();
// Запустити конкретний сідер...
$this->seed(OrderStatusSeeder::class);
// ...
// Запустити масив конкретних сідерів...
$this->seed([
OrderStatusSeeder::class,
TransactionStatusSeeder::class,
// ...
]);
}
}
Також можна наказати Laravel автоматично наповнювати базу перед кожним тестом, який використовує трейт RefreshDatabase. Для цього додайте атрибут Seed до базового класу тестів:
<?php
namespace Tests;
use Illuminate\Foundation\Testing\Attributes\Seed;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
#[Seed]
abstract class TestCase extends BaseTestCase
{
}
За наявності атрибута Seed перед кожним тестом, який використовує трейт RefreshDatabase, буде виконано клас Database\Seeders\DatabaseSeeder. Втім, ви можете вказати конкретний сідер для виконання через атрибут Seeder на класі тесту:
<?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 надає кілька тверджень про стан бази даних для ваших feature-тестів на Pest чи PHPUnit. Розглянемо кожне з них.
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-модель було «мʼяко видалено» (soft deleted):
$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);
// Тест...
Перекладаємо з офіційної документації, розділ за розділом, і не ховаємо недоперекладене. Помітили неточність у терміні чи реченні: напишіть, виправимо.