The Journey Towards Fast Laravel Tests
Here is a collection of articles and packages, that tackle the problem of speeding up Laravel tests.
They're here for reference, and will hopefully give some inspiration.
TIP
Please let me know if you know of any others!
Articles
Speeding up PHPUnit tests 15 times by Chris Duell - February 2014
- Create a migrated and seeded SQLite file as the starting point, use a copy of it for each test
- Use Grunt or Gulp to observe changes in migration and seeder files, which then re-creates the SQLite database
Speed up Laravel tests with database transactions by Jordan Eldredge - May 2014
- Create a custom bootstrap file to migrate and seed a database before tests run
- Wrap tests in a transaction that's rolled-back afterwards
Speeding up PHPunit tests and Behat in Laravel for Database refreshes by Alfred Nutile - November 2014
- Use a "setup" connection to prepare a fresh SQLite database in
- Copy this prepared database file for the "sqlite" connection to use
Laravel's
DatabaseMigrations
andDatabaseTransactions
traits were added in the Laravel 5.1.0 release - June 2015
SQLite In-Memory Database for Unit Tests in Laravel by Maurizio Bonani - February 2016
- Use
:memory:
SQLite databases
Stubbing Eloquent Relations for Faster Tests by Adam Wathan - August 2016
- Build Eloquent relationship data in memory instead of seeding the database
Two tips to speedup your Laravel tests by Dries Vints - August 2016
- Reduce password hashing rounds
- Use pre-generated hashes instead
A Better Database Testing Workflow in Laravel by Adam Wathan - November 2016
- Walk-through of a custom trait that migrates the test database once for the first test, and then runs each test in a transaction that's rolled-back afterwards (precursor to Laravel's
RefreshDatabase
trait)
Speed up your Laravel tests by 70% with this one simple trick by Dwight Watson - December 2016
- Migrate for the first test, wrap tests in a transaction that's rolled-back afterwards
My Suggestions to Speed up Testing with Laravel and PHPUnit by Nate Denlinger - August 2017
- Use
:memory:
SQLite databases- Migrate and seed a SQLite filesystem database, and use that as a starting point for each test
- Custom process to import a SQLite dump file into a
:memory:
database- Disable Xdebug
- Use SSDs instead of HDDs
Laravel's
RefreshDatabase
trait was added in the Laravel 5.5.0 release - August 2017
More tricks for speeding up your Laravel test suite by matthew daly - January 2018
- Reduce password hashing rounds
- Wrap seeders inside a transaction
- Migrate and Seed for the first test, wrap tests in a transaction that's rolled-back afterwards
- Use
PHPUnit\Framework\TestCase
instead of Laravel'sTests\TestCase
when possible- Use
:memory:
SQLite databases- Use Laravel's
RefreshDatabase
trait- Use mocks
- Offload functionality to separate packages in large projects
- Disable Xdebug - use CI to generate code coverage instead
Speed Up Your PHPUnit Tests – Disable Xdebug by Dustin Fraker - April 2018
- Disable Xdebug
Speed-up database refreshing in PHPUnit tests by Paula Čučuk - September 2018
- Create a migrated and seeded SQLite file as the starting point, use a copy of it for each test
- (Symfony) Create a command to create a sql-dump file of the migrated and seeded database (schema and fixtures), and then run your tests. Each test imports this sql file
- Wrap tests in a transaction that's rolled-back afterwards
How to speed up your PHPunit tests in Laravel 5? by Ivan Kolodii - October 2018
- Improve Factory usage
- Use minio instead of S3 so files are stored locally
- Mock 3rd party services
- Cache Laravel's config and routes
My feature test suite setup by Tim MacDonald - November 2018
- Don't use SQLite to increase speed, at the cost of accuracy
- Use Laravel's
DatabaseTransactions
trait along side ParaTest for parallel testing- Then use a composer command to migrate the database before running your tests
Speed up PHPUnit Code Coverage Analysis by Nicolas Cabot - December 2018
- Speed comparison between Xdebug, Phpdbg and PCov
How migrations might be slowing down your Laravel tests by Alex Vanderbist - January 2019
- Import a sql-dump file before running migrations, wrap tests in a transaction that's rolled-back afterwards
Tips to Speed up Your Phpunit Tests by Tim MacDonald - January 2019
- Use ParaTest to run tests in parallel
- Re-run only failed tests
- Run specific tests using filtering
- Group slow tests
- Reduce password hashing rounds
- Use
:memory:
SQLite databases - with a note about incompatibilities- Disable Xdebug
- Use PHPUnit Report to find slow tests
How to reduce your PHP tests execution time up to 85% by Rafael Monteiro - February 2019
- ParaTest configuration tweaks
Using MySQL for Testing (on Laravel) by Tony Messias - March 2019
- Use MySQL with Laravel's
RefreshDatabase
trait instead of SQLite:memory:
database- Use tmpfs for your database server's filesystem - with Docker example
The case of the Laravel TestCase by Tim MacDonald - June 2019
- Investigation in to caching Laravel's config when testing
Under the hood: How RefreshDatabase works in Laravel tests by Daniel Verner - August 2019
- Explanation of what the
RefreshDatabase
trait does- Don't commit the transaction
Laravel Schema Dump: how to speed up your migrations? by Robin Dirksen - April 2020
- How to use Laravel's new migration squashing command, coming to Laravel 8
Clean Up Migrations and Speed up Tests with the Schema Dump Command by Paul Redmond - April 2020
- Introduction to the new
php artisan schema:dump
command, coming to Laravel 8
Improve the Performance of Laravel Feature Tests using MySQL Instead of SQLite or Memory Databases by Owen Conti - May 2020
- SQLite
:memory:
databases can be slower than MySQL
One Trick to speed up your unit tests with Laravel by Acho Arnold - August 2020
- Use
PHPUnit\Framework\TestCase
instead of Laravel'sTests\TestCase
when possible
How to run over 30k tests in under 5 minutes by Daan van Marsbergen - September 2020
- Use ParaTest to run tests in parallel
- Mock external services, like RabbitMQ
- Use a bash script prepare multiple databases. Creates a sql-dump of a migrated MySQL database, then imports that into multiple other MySQL databases
- Then start the parallel tests
- Wrap tests in a transaction that's rolled-back afterwards
- Use phpunit-speedtrap to check for slow tests
- Use parallel GitLab pipelines
- Cache
vendor/
andnode_modules/
directories for GitLab pipeline runners to use- Run individual tests via PHPStorm
Laravel's migration squashing
php artisan schema:dump
command was added in the Laravel 8.0.0 release - September 2020
Speed up Feature tests in Laravel with docker-compose and tmpfs by Max - November 2020
- Run MySQL with a tmpfs (memory) file system
How to make PHPUnit Code Coverage 2+ times faster with Pcov compared to Xdebug by Geshan Manandhar - November 2020
- Speed Comparison between PCov and XDebug
Finding Slow Tests in PHPUnit 9 by Aaron Saray - January 2021
- Find slow tests by measuring the amount of time each one takes
Laravel added parallel testing by integrating ParaTest in the Laravel 8.25 release - January 2021
Making our Laravel test suite ready for parallel testing - by Freek Van der Herten - February 2021
- Considerations when running a tests in parallel
Make RefreshDatabase trait much faster by Ahmad Mayahi - June 2021
- Laravel's
RefreshDatabase
trait can be altered so that it only re-migrates (i.e.migrate:fresh
) upon start-up, when files in the migrations directory change
Speed up migrations when running Laravel tests by Grant - August 2021
- Testing the speed increase after squashing migrations
Running PHPUnit tests in parallel using GitHub actions by Rias - March 2022
- Breakdown of how to run tests in parallel, when using GitHub Actions
How to run your Laravel Dusk tests in parallel with GitHub Actions by Sjors Ottjes - March 2022
- Breakdown of how to run Dusk browser tests in parallel, when using GitHub Actions
Laravel Packages
NOTE
Many of these packages haven't been updated for a number of years.
Setup Test DB Command for Laravel - started January 2015
- Adds the
db:seed-test
command that creates a clean migrated and seeded database- Expects that you're using Laravel's
DatabaseTransactions
trait- A bootstrap file is included that runs
db:seed-test
automatically before running any tests- Requires a tweak to
phpunit.xml
to use this bootstrap file when running tests
Fast Laravel Testing - started March 2018
- Only for use with SQLite
- Adds the
ShouldFest
trait as a replacement for Laravel'sRefreshDatabase
- For the first test in the test-run, your migrations are run, and a sql-dump export is taken of the result
- Then your database connection's database is swapped to
:memory:
- The sql-dump is imported into the memory database
Laravel Quick Migrations - started July 2018
- Only for use with MySQL / MariaDB
- First, manually create your own sql-dump file
- Adds a
QuickDatabaseMigrations
trait to add to test-classes- It imports your sql-dump file for every test where this trait is present (by using a custom migration)
- Author Marcin Nabiałek published this article with further details
Refresh Database - started October 2018
- Only for use with SQLite
- (Not to be confused with Laravel's
RefreshDatabase
trait)- A bootstrap file is included that migrates the database/s when the test-run starts, SQLite dump/s are taken
- Requires a tweak to
phpunit.xml
to use this bootstrap file when running tests- These SQLite dumps are imported for every test that uses the
RefreshDatabase
trait- Uses the migration files' content for cache-busting
- Configured via yaml file
- Allows for multiple databases to be built (e.g. "shared" and "tenant")
RefreshAndSeedDatabase trait for Laravel - started November 2018
- Operates the same way as Laravel's
RefreshDatabase
but also seeds the database before starting the transaction (whichRefreshDatabase
didn't handle at the time)
RefreshAndSeedDatabase trait for Laravel - started November 2018
- Adds functionality like Laravel's
RefreshDatabase
trait, but includes seeding when performing the initial migration (Laravel has now added this functionality toRefreshDatabase
)
Snipe Migrations - started February 2019
- Only for use with MySQL / MariaDB
- Acts like Laravel's
RefreshDatabase
trait, but imports a sql-dump file when available- Adds the
SnipeMigrations
trait to add to test-classes- When
SnipeMigrations
and Laravel'sRefreshDatabase
are both encountered for the first time in a test-run, the database is prepared- The database is migrated and possibly seeded. A sql-dump export is taken of the result
- The next time the database is prepared, this sql-dump file is imported
- Uses the migration and seeder file modified times for cache-busting
- Author Dustin Fraker published this article with further details
Snap Migrations - started May 2019
- Only for use with MySQL / MariaDB. Uses
mysqli
- Adds the
SnapMigrations
trait to add to test-classes- When present in a test, it will migrate and possibly seed the database. A sql-dump export is taken of the result
- The sql-dump is imported for every test using
SnapMigrations
- Uses the most recently updated migration file time for cache-busting
- Compatible with Lumen as well as Laravel
laravel-test-snapshot - started March 2020
- Only for use with SQLite file databases
- Adds the
test:snapshot
command that migrates a SQLite database the first time it's run. A copy of this database file is stored for use later- Upon future runs, the previously built database file is copied, ready for use
- Uses a checksum based on the migration files' modified times for cache-busting
- A bootstrap file is included that clears Laravel's cache, runs config, route and event caching, and runs the
test:snapshot
command- Requires a tweak to
phpunit.xml
to use this bootstrap file when running tests
quick-laravel-migrations - started July 2020
- Only for use with MySQL / MariaDB
- Provides the
db:dump
command to create a sql-dump file of the structure, and another for the data, from the DB_DATABASE defined in.env
- Adds the
QuickDatabaseMigrations
trait as a replacement for Laravel'sDatabaseMigrations
- When present in a test, it imports the structure sql-dump file, and possibly the data sql-dump file
- Adds the
db:load
command, this also imports the structure sql-dump file, and possibly the data sql-dump file- Note: Requires
db:dump
to be run manually after migrations or seeders have been updated- Note: Has no tagged releases