Как использовать 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;
}

 

На этом всё. Успехов!