-
-
Save adamwathan/dd46a8501097942a771925c02bac0111 to your computer and use it in GitHub Desktop.
A Better Database Testing Workflow in Laravel
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
use Illuminate\Contracts\Console\Kernel; | |
trait DatabaseSetup | |
{ | |
protected static $migrated = false; | |
public function setupDatabase() | |
{ | |
if ($this->isInMemory()) { | |
$this->setupInMemoryDatabase(); | |
} else { | |
$this->setupTestDatabase(); | |
} | |
} | |
protected function isInMemory() | |
{ | |
return config('database.connections')[config('database.default')]['database'] == ':memory:'; | |
} | |
protected function setupInMemoryDatabase() | |
{ | |
$this->artisan('migrate'); | |
$this->app[Kernel::class]->setArtisan(null); | |
} | |
protected function setupTestDatabase() | |
{ | |
if (! static::$migrated) { | |
$this->artisan('migrate:refresh'); | |
$this->app[Kernel::class]->setArtisan(null); | |
static::$migrated = true; | |
} | |
$this->beginDatabaseTransaction(); | |
} | |
public function beginDatabaseTransaction() | |
{ | |
$database = $this->app->make('db'); | |
foreach ($this->connectionsToTransact() as $name) { | |
$database->connection($name)->beginTransaction(); | |
} | |
$this->beforeApplicationDestroyed(function () use ($database) { | |
foreach ($this->connectionsToTransact() as $name) { | |
$database->connection($name)->rollBack(); | |
} | |
}); | |
} | |
protected function connectionsToTransact() | |
{ | |
return property_exists($this, 'connectionsToTransact') | |
? $this->connectionsToTransact : [null]; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
abstract class TestCase extends Illuminate\Foundation\Testing\TestCase | |
{ | |
use DatabaseSetup; | |
/** | |
* The base URL to use while testing the application. | |
* | |
* @var string | |
*/ | |
protected $baseUrl = 'http://localhost'; | |
protected function setUp() | |
{ | |
parent::setUp(); | |
$this->setupDatabase(); | |
} | |
/** | |
* Creates the application. | |
* | |
* @return \Illuminate\Foundation\Application | |
*/ | |
public function createApplication() | |
{ | |
$app = require __DIR__.'/../bootstrap/app.php'; | |
$app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap(); | |
return $app; | |
} | |
} |
@adamwathan For learning purposes, can I ask what the technical reason is for $this->app[Kernel::class]->setArtisan(null);
?
Note that Laravel has a build in trait \Illuminate\Foundation\Testing\RefreshDatabase
(formerly added as FreshDatabase) that has the same logic
Yeah, looks like it's not needed anymore in recent Laravel versions.
awesome
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@adamwathan Would it be better to only run refresh if migrations actually change?
Something like this?
https://gist.github.com/slava-vishnyakov/2ae1d1e030204ad10c1898b20aeba4cb#file-databasesetup-php-L33-L36
https://gist.github.com/slava-vishnyakov/2ae1d1e030204ad10c1898b20aeba4cb#file-databasesetup-php-L61-L77
https://gist.github.com/slava-vishnyakov/2ae1d1e030204ad10c1898b20aeba4cb/revisions?diff=split
For my app
refresh
takes 3.5 seconds :( So this really speeds up the process.