Як використовувати SQLite для тестування в Laravel

Як використовувати SQLite для тестування в Laravel

Трохи загальної інформації про тестування в Laravel і про те, як використовувати для цих цілей SQLite.

ОС: Ubuntu 18.04. Laravel: 5.8. SQLite: 3.22

Про тестування

Підтримка phpunit в Laravel вже вбудована, включаючи налаштування в файлі phpunit.xml. У корені проекту знаходиться директорія tests c двома піддиректоріями - Feature і Unit. Якщо вже зовсім коротко, то:

  • Unit тести (вони ж модульні тести) призначені для тестування окремого, ізольованого модуля (наприклад, методу, функції) з усіма mockup-залежностями.
  • Feature тести (функціональні тести, інтеграційні тести) потрібні для тестування будь-якої частини функціоналу системи, можуть взаємодіяти з базами даних, сервісами і т.д. Можуть перевіряти взаємодію об'єктів один з одним, HTTP-запити і т.д.

Простіше кажучи: є дві сутності - категорія і товар. Ми написали тести, які перевіряють кожну з них - це модульні тести. Якщо ж хочемо перевірити як ці сутності взаємодіють і чи нічого не зламається - пишемо функціональні тести.

Модульні тести створюються командою:

php artisan make:test MyModuleTest --unit

 

Для створення функціонального тесту слід виконати:

php artisan make:test MyFeatureTest

 

Методи в класах тестів повинні починатися зі слова test (причому для назви методу може Використовувати як camelCase, так і snake_case), або над методом повинен бути прописаний php dockblock @test. Приклади валидного коду:

public function testUserCanCreatePost() {}

public function test_user_can_create_post() {}

/**
 * @test
 */
public function userCanCreatePost() {}

 

Запускаються тести з кореня проекту командою:

vendor/bin/phpunit

 

Можна запускати як тест окремого класу, так і тестувати будь-якої окремий метод. Дані опції відносяться не до Laravel, а до PHPUnit, тому як завжди пропоную ознайомитися с документацією.

Важливо: недонократно стикався з тим, що люди забувають про те, що тести повинні бути незалежними. Іншими словами, кожен метод кожного тестового класу повинен працювати в незалежності від того, чи були запущені інші тести чи ні. Помилка, що часто зустрічається - один метод покладається на якусь частину коду, яка була написана в одному з попередніх методів. Наприклад, в методі є такий код:

$user = factory(User::class)->state('admin')->create();
$this->actingAs($user)

 

І наступний метод розраховуватими на те, що дії будуть виконані користувачем-адміном.

Що стосується оточення - при запуску тестів, фреймворк автоматично встановить змінні середовища, які визначені в phpunit.xml. Також для сесій і кеша драйвером буде встановлено масив, відповідно дані сесій і кешу не будуть зберігатися. Ще одна опція - створити файл .env.testing і вказати в ньому змінні, які треба перевизначити під час тестування. Слід згадати рекомендацію (з оф доків) обов'язково очищати кеш конфігурації перед запуском тестів:

php artisan config:clear

 

Використання SQLite

Що стосується тестів, які потребують "спілкування" з базами даних, - особисто я на практиці стикався з двома варіантами. Перший - просто створюється база даних для тестування. Використовуємо в проекті PostgreSQL - значить створюємо тестову базу PostgreSQL, використовуємо MySQL - створимо тестову базу MySQL і т.д. Хоча тести займають більше часу, але при такому підході ми можемо бути впевнені, що не виникне ніяких нюансів, пов'язаних з різною реалізацією (вибачте за тавтологію) різних баз даних.

Другий варіант - використання SQLite in memory. Тобто фізично база даних не створюється - всі дані під час тестування зберігаються в пам'яті, що позитивно позначається на тривалості виконання тестів. Треба визнати, що даний спосіб досить поширений, оскільки в реальному житті не так часто розробники використовують ті можливості БД, які не дозволяють підмінити використовувану базу на SQLite при тестуванні.

Почнемо з установки. Оновимо кеш репозиторія пакетів apt:

sudo apt-get update

 

Потім поставимо SQLite 3:

sudo apt-get install sqlite3

 

Перевіримо, чи працює SQLite:

sqlite3 --version

 

В результаті виконання команди ми повинні побачити приблизно наступне:

3.22.0 2018-01-22 18:45:57 0c55d179733b46d8d0ba4d88e01a25e10677046ee3da1d5b1581e86726f2alt1

 

Виконайте:

php -i|grep PDO

 

Якщо не бачите PDO драйвера для SQLite, то знадобиться ще одна команда для його інсталяції під Вашу версію php (в моєму випадку 7.3):

sudo apt-get install php7.3-sqlite3

 

Якщо є бажання, таже можна поставити графічну оболонку SQLite Browser (після установки для запуску цього інструменту треба зайти в меню додатків і набрати в поле пошуку SQLite Browser, вибрати його і натиснути Enter):

sudo apt-get install sqlitebrowser

 

Як використовувати в Laravel тестах

В розділ Database Connections файлу config/database.php додамо:

'sqlite_memory' => [
    'driver' => 'sqlite',
    'database' => ':memory:',
    'prefix' => '',
]

 

Потім пропишемо пару рядків в phpunit.xml:

<env name="DB_CONNECTION" value="sqlite_memory"/>
<env name="DB_DATABASE" value=":memory:"/>

 

Примітка: якщо в проекті використовується Telescope, також слід додати і такий рядок:

<env name="TELESCOPE_ENABLED" value="false"/>

 

Тобто блок php файлу буде виглядати так:

<php>
    <env name="APP_ENV" value="testing"/>
    <env name="DB_CONNECTION" value="sqlite_memory"/>
    <env name="DB_DATABASE" value=":memory:"/>
    <env name="BCRYPT_ROUNDS" value="4"/>
    <env name="CACHE_DRIVER" value="array"/>
    <env name="MAIL_DRIVER" value="array"/>
    <env name="QUEUE_CONNECTION" value="sync"/>
    <env name="SESSION_DRIVER" value="array"/>
    <env name="TELESCOPE_ENABLED" value="false"/>
</php>

 

І останнє - для запуску міграцій додамо трейт DatabaseMigrations:

<?php

namespace Tests;

use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;

abstract class TestCase extends BaseTestCase
{
    use CreatesApplication, DatabaseMigrations;
}

 

На цьому все. Успіхів!