Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
A Better Database Testing Workflow in Laravel
<?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->whenMigrationsChange(function() {
$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];
}
protected function getMigrationsMd5()
{
return md5(collect(glob(base_path('database/migrations/*')))
->map(function ($f) {
return file_get_contents($f);
})->implode(''));
}
protected function whenMigrationsChange($callback)
{
$md5 = $this->getMigrationsMd5();
$path = storage_path('app/migrations_md5.txt');
if(!file_exists($path) || ($md5 !== file_get_contents($path))) {
$callback();
file_put_contents($path, $md5);
}
}
}
<?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;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.