Введение
Laravel предоставляет множество полезных инструментов для тестирования ваших приложений, использующих БД. Во-первых, вы можете использовать вспомогательный метод PHPseeInDatabase()
для проверки того, что данные в БД соответствуют определённому набору критериев. Например, если вы хотите проверить, что в таблице users есть запись с полем email равным sally@example.com, вы можете сделать следующее:
public function testDatabase()
{
// Осуществление вызова приложения...
$this->seeInDatabase('users', [
'email' => 'sally@example.com'
]);
}
Само собой, такие методы как PHPseeInDatabase()
созданы для удобства. Вы можете использовать любые встроенные методы проверки PHPUnit для дополнения своих тестов.
Сброс БД после каждого теста
Зачастую бывает полезно сбрасывать вашу БД после каждого теста, чтобы данные из предыдущего теста не влияли на последующие тесты.
Использование миграций
Один из способов сброса состояния БД — откатывать БД после каждого теста и мигрировать её перед следующим тестом. Laravel предоставляет простой типаж DatabaseMigrations, который автоматически сделает это для вас. Просто используйте этот типаж на классе вашего теста, и всё будет сделано за вас:
<?php
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ExampleTest extends TestCase
{
use DatabaseMigrations;
/**
* Пример базового функционального теста.
*
* @return void
*/
public function testBasicExample()
{
$this->visit('/')
->see('Laravel 5');
}
}
Использование транзакций
Другой способ сброса состояния БД — обернуть каждый тест-кейс в транзакцию БД. И для этого Laravel также предоставляет удобный типаж DatabaseTransactions, который автоматически сделает это для вас:
<?php
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ExampleTest extends TestCase
{
use DatabaseTransactions;
/**
* Пример базового функционального теста.
*
* @return void
*/
public function testBasicExample()
{
$this->visit('/')
->see('Laravel 5');
}
}
По умолчанию этот типаж будет оборачивать в транзакции только подключение к БД по умолчанию. Если ваше приложение использует несколько подключений к БД, вам надо определить свойство PHP$connectionsToTransact
в классе вашего теста. Это свойство должно быть массивом имён подключений для выполнения транзакций над ними.
Создание фабрик
При тестировании вам может понадобиться вставить несколько записей в вашу БД перед выполнением теста. При создании этих данных Laravel позволяет вам вместо указания значений каждого столбца вручную определить стандартный набор атрибутов для каждой из ваших моделей Eloquent с помощью фабрик. Для начала посмотрите на файл database/factories/ModelFactory.php в вашем приложении. Изначально этот файл содержит определение одной фабрики:
$factory->define(App\User::class, function (Faker\Generator $faker) {
static $password;
return [
'name' => $faker->name,
'email' => $faker->unique()->safeEmail,
'password' => $password ?: $password = bcrypt('secret'),
'remember_token' => str_random(10),
];
});
В замыкании, которое служит определением фабрики, вы можете вернуть стандартные тестовые значения всех атрибутов модели. Замыкание получит экземпляр PHP-библиотеки Faker, которая позволяет вам удобно генерировать различные случайные данные для тестирования.
Само собой, вы можете добавить свои собственные дополнительные фабрики в файл ModelFactory.php. Также вы можете создать дополнительные файлы фабрик для каждой модели для более понятной организации. Например, вы можете создать файлы UserFactory.php и CommentFactory.php в вашей папке database/factories. Все файлы в папке factories будут автоматически загружены Laravel.
Состояния фабрик
Состояния позволяют вам определить отдельные изменения, которые можно применять к вашим фабрикам моделей в любых комбинациях. Например, ваша модель User может иметь состояние delinquent (нарушитель), которое изменяет стандартное значение одного из атрибутов. Вы можете определить свои преобразования состояния с помощью метода PHPstate()
:
$factory->state(App\User::class, 'delinquent', function ($faker) {
return [
'account_status' => 'delinquent',
];
});
Использование фабрик
Создание моделей
После определения фабрик вы можете использовать глобальную функцию PHPfactory()
в своих тестах или файлах начальных данных для генерирования экземпляров модели. Итак, давайте рассмотрим несколько примеров создания моделей. Во-первых, мы используем метод PHPmake()
для создания моделей, но не сохраним их в БД:
public function testDatabase()
{
$user = factory(App\User::class)->make();
// Использование модели в тестах...
}
Также вы можете создать коллекцию моделей или создать модели определённого типа:
// Создание трёх экземпляров App\User...
$users = factory(App\User::class, 3)->make();
Также вы можете применить любые состояния к моделям. Если вы хотите применить к моделям несколько изменений состояния, вам надо указать имя каждого состояния для применения:
$users = factory(App\User::class, 5)->states('delinquent')->make();
$users = factory(App\User::class, 5)->states('premium', 'delinquent')->make();
Если вы хотите переопределить некоторые из стандартных значений ваших моделей, вы можете передать массив значений в метод PHPmake()
. Будут заменены только указанные значения, а остальные будут заданы в соответствии с указанными в фабрике:
$user = factory(App\User::class)->make([
'name' => 'Abigail',
]);
Постоянные модели
Метод PHPcreate()
не только создаёт экземпляры моделей, но также сохраняет их в БД с помощью метода Eloquent PHPsave()
:
public function testDatabase()
{
// Создание одного экземпляра App\User...
$user = factory(App\User::class)->create();
// Создание трёх экземпляров App\User...
$users = factory(App\User::class, 3)->create();
// Использование модели в тестах...
}
Вы можете переопределить атрибуты модели, передав массив в метод PHPcreate()
:
$user = factory(App\User::class)->create([
'name' => 'Abigail',
]);
Отношения
В этом примере мы прикрепим отношение к некоторым созданным моделям. При использовании метода PHPcreate()
для создания нескольких моделей возвращается экземпляр коллекции Eloquent, позволяя вам использовать все удобные функции для работы с коллекцией, такие как PHPeach()
:
$users = factory(App\User::class, 3)
->create()
->each(function ($u) {
$u->posts()->save(factory(App\Post::class)->make());
});
Отношения и атрибуты замыкания
Также вы можете прикреплять отношения к моделям с помощью атрибутов замыкания в определениях ваших фабрик. Например, если вы хотите создать новый экземпляр модели User при создании Post, то можете сделать так:
$factory->define(App\Post::class, function ($faker) {
return [
'title' => $faker->title,
'content' => $faker->paragraph,
'user_id' => function () {
return factory(App\User::class)->create()->id;
}
];
});
Это замыкание также получает определённый массив атрибутов фабрики, которая его содержит:
$factory->define(App\Post::class, function ($faker) {
return [
'title' => $faker->title,
'content' => $faker->paragraph,
'user_id' => function () {
return factory(App\User::class)->create()->id;
},
'user_type' => function (array $post) {
return App\User::find($post['user_id'])->type;
}
];
});