Giter Site home page Giter Site logo

laravel-fast-refresh-database's Introduction

FastRefreshDatabase for Laravel πŸš€

Have you ever come across an issue where the traditional RefreshDatabase trait takes ages to run tests when you have lots of migrations? If so, you may be after this package!

The Problem

Traditionally, the RefreshDatabase trait will run php artisan migrate:fresh every time you run tests. After the first test, it will use transactions to roll back the data and run the next one, so subsequent tests are fast, but the initial test is slow. This can be really annoying if you are used to running a single test, as it could take seconds to run a single test.

The Solution

You don't need to run php artisan migrate:fresh every time you run tests, only when you add a new migration or change an old one. The FastRefreshDatabase trait will create a checksum of your migrations folder as well as your current Git branch. It will then create a checksum file in your application's storage/app directory. When your migrations change or your branch changes, the checksum won't match the cached one and php artisan migrate:fresh is run.

When you don't make any changes, it will continue to use the same database without refreshing, which can speed up the test time by 100x!

Benchmarks

Running a single test, with about 400 migrations.

Processor Before After
Intel Core i5 30 seconds 100 milliseconds
Apple M1 Pro 5 seconds 100 milliseconds

Installation

Install the package with Composer

composer require plannr/laravel-fast-refresh-database --dev

Adding to your TestCase

Next, just replace the existing RefreshDatabase trait you are using in your TestCase file with the FastRefreshDatabase trait

<?php

namespace Tests;

use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
-use Illuminate\Foundation\Testing\RefreshDatabase;
+use Plannr\Laravel\FastRefreshDatabase\Traits\FastRefreshDatabase;

abstract class TestCase extends BaseTestCase
{
    use CreatesApplication;
-   use RefreshDatabase;
+   use FastRefreshDatabase;
}

Using Pest

Just replace the uses line in your Pest.php file

-use Illuminate\Foundation\Testing\RefreshDatabase;
+use Plannr\Laravel\FastRefreshDatabase\Traits\FastRefreshDatabase;

-uses(RefreshDatabase::class)->in(__DIR__);
uses(FastRefreshDatabase::class)->in('Feature');

Deleting The Migration Checksum

Sometimes you may wish to force-update database migrations, to do this, locate the migration-checksum_{Database Name Slug}.txt file within storage/app.

Customising the checksum file location

You may customise the migration checksum file location and name by extending the trait and overwriting the getMigrationChecksumFile() method.

protected function getMigrationChecksumFile(): string
{
    return storage_path('custom/some-other-file.txt');
}

ParaTest Databases

Parallel testing databases contain tokens that serve as unique identifiers for each test runner. This makes the trait inherently able to support parallel testing without any extra effort, because the database name is stored in the checksum file name.

laravel-fast-refresh-database's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

laravel-fast-refresh-database's Issues

migrationsChecksum.txt should be added to the root .gitignore file

It would be good to add the migrationChecksum.txt to the gitignore file in the project root when installing the package.
If that is possible that is.

Love the package and I use it in my main project, and I'm very happy with how it performs so far.
Good job guys.

[Discussion]Β Store migration with database name

I wanted to put this up for discussion before actually sending a PR.
Currently this package doesn't really support parallel testing reliably. I was exploring a few ways this could be solved. One option I really like is just appending the database name to the migration checksum file.

This basically allows you to switch between parallel and sequential testing as each database has its own checksum store. There would be no need to ever delete the migration checksum file. It would just work out of the box.

I think this makes a lot of sense, as the trait is ran per worker process which has a dedicated database. So ideally we store this information too.

I think changing this method to something as simple as

    protected function getMigrationChecksumFile(): string
    {
        $databaseName = \DB::connection()->getDatabaseName();
    
        return storage_path("app/migrationChecksum-{$databaseName}.txt");
    }

should already work.
Note: Not sure if the DB name can always be stored in a filesystem, so this should probably be processed. Also using the DB facade isn't as clean, as we have access to $this->app

What do you think of this?

RefreshDatabase and FastRefreshDatabase is not workable with Laravel Dusk

I would avoid the __DIR__ variable in the Pest file

+uses(FastRefreshDatabase::class)->in(__DIR__);

due the RefreshDatabase trait is not compatible with Laravel Dusk, which uses only the DatabaseMigrations trait. Source: https://laravel.com/docs/9.x/dusk#migrations.
My suggestion to document:
uses(FastRefreshDatabase::class)->in('Feature');
instead of
uses(FastRefreshDatabase::class)->in(__DIR__);

getCachedMigrationChecksum always returns null

For some odd reason, the getCachedMigrationChecksum method returns null when using the rescue method:

protected function getCachedMigrationChecksum(): ?string
{
    return rescue(static fn () => file_get_contents($this->getMigrationChecksumFile()), null, false);
}

// null

When I change it to only use file_get_contents($this->getMigrationChecksumFile()) it works fine.

protected function getCachedMigrationChecksum(): ?string
{
    return file_get_contents($this->getMigrationChecksumFile());
}

// d99e0d21f2061fbe53ae73fb885...

No idea why it does this or how to fix it.

Let me know if you need more info!

Not really an issue just an possible speed upgrade

In many of my test files I run a before each function where I seed a static table.
The content of this table would never change from inside the application.

beforeEach(function () {
  $this->seed(MediaTypeSeeder::class);
});

So my thought is that if it somehow would be possible to add some kind of FastTableSeeder trait. that takes an array of seeder classes and keeps track of the checksum, and only runs them if needed, just like the migration:fresh.

In my case we are talking about 4 records, but for around 300 tests it becomes 1200 inserts, which takes time.

And maybe you want to be able force a run for each test file in the suite.

possible way tp fix paratest known issue

is there a way to delete the checksum, when a user asks for the parallel test?

for example when the user ran
PHP artisan test -p
always delete the checksum first.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.