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 knowopen in new window if you know of any others!

Articles

Speeding up PHPUnit tests 15 timesopen in new window by Chris Duellopen in new window - 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 transactionsopen in new window by Jordan Eldredgeopen in new window - 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 refreshesopen in new window by Alfred Nutileopen in new window - 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 and DatabaseTransactions traits were added in the Laravel 5.1.0 releaseopen in new window - June 2015

SQLite In-Memory Database for Unit Tests in Laravelopen in new window by Maurizio Bonaniopen in new window - February 2016

  • Use :memory: SQLite databases

Stubbing Eloquent Relations for Faster Testsopen in new window by Adam Wathanopen in new window - August 2016

  • Build Eloquent relationship data in memory instead of seeding the database

Two tips to speedup your Laravel testsopen in new window by Dries Vintsopen in new window - August 2016

  • Reduce password hashing rounds
  • Use pre-generated hashes instead

A Better Database Testing Workflow in Laravelopen in new window by Adam Wathanopen in new window - 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 trickopen in new window by Dwight Watsonopen in new window - 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 PHPUnitopen in new window by Nate Denlingeropen in new window - 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 releaseopen in new window - August 2017

More tricks for speeding up your Laravel test suiteopen in new window by matthew dalyopen in new window - 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's Tests\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 Xdebugopen in new window by Dustin Frakeropen in new window - April 2018

  • Disable Xdebug

Speed-up database refreshing in PHPUnit testsopen in new window by Paula Čučukopen in new window - 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?open in new window by Ivan Kolodiiopen in new window - 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 setupopen in new window by Tim MacDonaldopen in new window - 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 Analysisopen in new window by Nicolas Cabotopen in new window - December 2018

  • Speed comparison between Xdebug, Phpdbg and PCov

How migrations might be slowing down your Laravel testsopen in new window by Alex Vanderbistopen in new window - 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 Testsopen in new window by Tim MacDonaldopen in new window - 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%open in new window by Rafael Monteiroopen in new window - February 2019

  • ParaTest configuration tweaks

Using MySQL for Testing (on Laravel)open in new window by Tony Messiasopen in new window - 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 TestCaseopen in new window by Tim MacDonaldopen in new window - June 2019

  • Investigation in to caching Laravel's config when testing

Under the hood: How RefreshDatabase works in Laravel testsopen in new window 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?open in new window by Robin Dirksenopen in new window - 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 Commandopen in new window by Paul Redmondopen in new window - 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 Databasesopen in new window by Owen Contiopen in new window - May 2020

  • SQLite :memory: databases can be slower than MySQL

One Trick to speed up your unit tests with Laravelopen in new window by Acho Arnoldopen in new window - August 2020

  • Use PHPUnit\Framework\TestCase instead of Laravel's Tests\TestCase when possible

How to run over 30k tests in under 5 minutesopen in new window by Daan van Marsbergenopen in new window - 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/ and node_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 releaseopen in new window - September 2020

Speed up Feature tests in Laravel with docker-compose and tmpfsopen in new window by Maxopen in new window - November 2020

  • Run MySQL with a tmpfs (memory) file system

How to make PHPUnit Code Coverage 2+ times faster with Pcov compared to Xdebugopen in new window by Geshan Manandharopen in new window - November 2020

  • Speed Comparison between PCov and XDebug

Finding Slow Tests in PHPUnit 9open in new window by Aaron Sarayopen in new window - 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 releaseopen in new window - January 2021

Making our Laravel test suite ready for parallel testingopen in new window - by Freek Van der Hertenopen in new window - February 2021

  • Considerations when running a tests in parallel

Make RefreshDatabase trait much fasteropen in new window by Ahmad Mayahiopen in new window - 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 testsopen in new window by Grantopen in new window - August 2021

  • Testing the speed increase after squashing migrations

Running PHPUnit tests in parallel using GitHub actionsopen in new window by Riasopen in new window - 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 Actionsopen in new window by Sjors Ottjesopen in new window - 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 Laravelopen in new window - 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 Testingopen in new window - started March 2018

  • Only for use with SQLite
  • Adds the ShouldFest trait as a replacement for Laravel's RefreshDatabase
  • 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 Migrationsopen in new window - 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 articleopen in new window with further details

Refresh Databaseopen in new window - 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 Laravelopen in new window - started November 2018

  • Operates the same way as Laravel's RefreshDatabase but also seeds the database before starting the transaction (which RefreshDatabase didn't handle at the time)

RefreshAndSeedDatabase trait for Laravelopen in new window - started November 2018

Snipe Migrationsopen in new window - 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's RefreshDatabase 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 articleopen in new window with further details

Snap Migrationsopen in new window - 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-snapshotopen in new window - 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-migrationsopen in new window - 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's DatabaseMigrations
  • 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