{{TOC}} {{DOCVER 5.3=c06d6a2352ed8c767633aab9c20f2bf7d880c967 28.01.2017 5:00:51}} == Введение == Laravel предоставляет множество полезных инструментов для тестирования ваших приложений, использующих БД. Во-первых, вы можете использовать вспомогательный метод %%seeInDatabase()%% для проверки того, что данные в БД соответствуют определённому набору критериев. Например, если вы хотите проверить, что в таблице %%(t)users%% есть запись с полем %%(t)email%% равным %%(t)sally@example.com%%, вы можете сделать следующее: %% public function testDatabase() { // Осуществление вызова приложения... $this->seeInDatabase('users', [ 'email' => 'sally@example.com' ]); } %% Само собой, такие методы как %%seeInDatabase()%% созданы для удобства. Вы можете использовать любые встроенные методы проверки PHPUnit для дополнения своих тестов. == Сброс БД после каждого теста == Зачастую бывает полезно сбрасывать вашу БД после каждого теста, чтобы данные из предыдущего теста не влияли на последующие тесты. === Использование миграций === Один из способов сброса состояния БД - откатывать БД после каждого теста и мигрировать её перед следующим тестом. Laravel предоставляет простой типаж %%(t)DatabaseMigrations%%, который автоматически сделает это для вас. Просто используйте этот типаж на классе вашего теста, и всё будет сделано за вас: %% visit('/') ->see('Laravel 5'); } } %% === Использование транзакций === Другой способ сброса состояния БД - обернуть каждый тест-кейс в транзакцию БД. И для этого Laravel также предоставляет удобный типаж %%(t)DatabaseTransactions%%, который автоматически сделает это для вас: %% visit('/') ->see('Laravel 5'); } } %% .(alert) По умолчанию этот типаж будет оборачивать в транзакции только подключение к БД по умолчанию. Если ваше приложение использует несколько подключений к БД, вам надо определить свойство %%$connectionsToTransact%% в классе вашего теста. Это свойство должно быть массивом имён подключений для выполнения транзакций над ними. == ((#writing-factories)) Создание фабрик == При тестировании вам может понадобиться вставить несколько записей в вашу БД перед выполнением теста. При создании этих данных Laravel позволяет вам вместо указания значений каждого столбца вручную определить стандартный набор атрибутов для каждой из ваших ((//docs/v5/eloquent моделей Eloquent)) с помощью фабрик. Для начала посмотрите на файл %%(t)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-библиотеки ((https://github.com/fzaninotto/Faker Faker)), которая позволяет вам удобно генерировать различные случайные данные для тестирования. Само собой, вы можете добавить свои собственные дополнительные фабрики в файл %%(t)ModelFactory.php%%. Также вы можете создать дополнительные файлы фабрик для каждой модели для более понятной организации. Например, вы можете создать файлы %%(t)UserFactory.php%% и %%(t)CommentFactory.php%% в вашей папке %%(t)database/factories%%. Все файлы в папке %%(t)factories%% будут автоматически загружены Laravel. ((#состояния)) === Состояния фабрик === Состояния позволяют вам определить отдельные изменения, которые можно применять к вашим фабрикам моделей в любых комбинациях. Например, ваша модель %%(t)User%% может иметь состояние %%(t)delinquent%% (нарушитель), которое изменяет стандартное значение одного из атрибутов. Вы можете определить свои преобразования состояния с помощью метода %%state()%%: %% $factory->state(App\User::class, 'delinquent', function ($faker) { return [ 'account_status' => 'delinquent', ]; }); %% == Использование фабрик == === Создание моделей === После определения фабрик вы можете использовать глобальную функцию %%factory()%% в своих тестах или файлах начальных данных для генерирования экземпляров модели. Итак, давайте рассмотрим несколько примеров создания моделей. Во-первых, мы используем метод %%make()%% для создания моделей, но не сохраним их в БД: %% 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(); %% **Переопределение атрибутов** Если вы хотите переопределить некоторые из стандартных значений ваших моделей, вы можете передать массив значений в метод %%make()%%. Будут заменены только указанные значения, а остальные будут заданы в соответствии с указанными в фабрике: %% $user = factory(App\User::class)->make([ 'name' => 'Abigail', ]); %% === Постоянные модели === Метод %%create()%% не только создаёт экземпляры моделей, но также сохраняет их в БД с помощью метода Eloquent %%save()%%: %% public function testDatabase() { // Создание одного экземпляра App\User... $user = factory(App\User::class)->create(); // Создание трёх экземпляров App\User... $users = factory(App\User::class, 3)->create(); // Использование модели в тестах... } %% Вы можете переопределить атрибуты модели, передав массив в метод %%create()%%: %% $user = factory(App\User::class)->create([ 'name' => 'Abigail', ]); %% === Отношения === В этом примере мы прикрепим отношение к некоторым созданным моделям. При использовании метода %%create()%% для создания нескольких моделей возвращается ((//docs/v5/eloquent-collections экземпляр коллекции)) Eloquent, позволяя вам использовать все удобные функции для работы с коллекцией, такие как %%each()%%: %% $users = factory(App\User::class, 3) ->create() ->each(function ($u) { $u->posts()->save(factory(App\Post::class)->make()); }); %% **Отношения и атрибуты замыкания** Также вы можете прикреплять отношения к моделям с помощью атрибутов замыкания в определениях ваших фабрик. Например, если вы хотите создать новый экземпляр модели %%(t)User%% при создании %%(t)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; } ]; }); %%