
Как использовать SQLite для тестирования в Laravel
22.05.2019 19:31 | 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;
}
На этом всё. Успехов!