Некоторое время назад обнаружил статью, где показывалось, что трейт 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 работать вообще не будут. Но в целом этот трюк на длинной дистанции (особенно, с не очень быстрым компьютером) сэкономит прилично времени.