Студия разработки сайтов и приложений

Netspark.ru

Laravel, PHPUnit и Sqlite

Некоторое время назад обнаружил статью, где показывалось, что трейт RefreshDatabase в тестах позволяет им (тестам) работать с MySQL быстрее, чем с Sqlite в режиме memory. Это выглядело странно и почти немыслимо, но оказалось, что, действительно, так и есть. Перевёл в нескольких проектах юнит-тесты с Sqlite на MySQL, заменил трейт с DatabaseMigrations на RefreshDatabase, и полный пакет тестов стал выполняться в среднем на ~30% быстрее (плюс большая совместимость с реальной средой достигается).

Работает оно быстрее — потому что трейт позволяет не поднимать все миграции заново в каждом тесте, а просто очищать уже созданные один раз таблицы. Но у этого достоинства есть, конечно, и логическое продолжение. Очевидный недостаток в том, что один раз создать эти таблицы всё же нужно. И это будет точно медленнее, чем в sqlite.

Соответственно, если ты практикуешь TDD, то в ходе разработки гораздо чаще запускаешь не полный пакет юнит-тестов, а какой-то один тест, верифицирующий тот кусок функционала, над которым, собственно, ты работаешь. И тут, за счет скорости развертывания миграций, MySQL очень сильно проигрывает.

Решить эту проблему, однако, очень просто. Нужно в «режиме TDD», то есть при запуске отдельного теста, использовать другой конфиг. В котором вместо MySQL подставлен sqlite:

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

И запускать тест так:

phpunit -c phpunit_sqlite.xml <путь к тесту>

А чтобы не обламываться, что приходится каждый раз набирать ключик и путь к конфигу, нужно заменить эту команду простеньким синонимом:

alias tdd="phpunit -c phpunit_sqlite.xml"

Понятно, работать будет не для всех случаев. Например, если какой-нибудь из пакетов (spatie/laravel-tags, скажем) использует нативную поддержку JSON в MySQL, тесты этого функционала в sqlite работать вообще не будут. Но в целом этот трюк на длинной дистанции (особенно, с не очень быстрым компьютером) сэкономит прилично времени.

Комментарии