Skip to content

Instantly share code, notes, and snippets.

@benrowe
Last active July 26, 2020 08:40
Show Gist options
  • Save benrowe/e6fec8be7ff07b3a00506ed23635f4cc to your computer and use it in GitHub Desktop.
Save benrowe/e6fec8be7ff07b3a00506ed23635f4cc to your computer and use it in GitHub Desktop.
Run laravel tests with mysql

Run laravel tests efficiently with mysql

Injects a command into the phpunit bootstrap to seralise the migrated database state to an sql file.

Then on every test case, reset the database using the generated file.

Everytime phpunit runs, the test:bootstrap command is executed.

This will check for the existance of a sql file and if not, it creates a temporary database, migrates into the database and dumps the final migration to a sql file.

Then before every test case is ran, it will then use that sql file and replace the testing db with the contents of that sql file.

<?php
declare(strict_types=1);
namespace App\Console\Commands\Test;
use Illuminate\Console\Command;
use Illuminate\Contracts\Config\Repository;
use Illuminate\Support\Facades\DB;
class TestBootstrapCommand extends Command
{
private const DB_CONN = 'testing_tmp';
private const SQL_FILE_TTL = 3600;
protected $signature = 'test:bootstrap';
/**
* @var Repository
*/
private $config;
public function __construct(Repository $config)
{
$this->config = $config;
parent::__construct();
}
public function handle()
{
$sqlFile = storage_path('tmp.sql');
if (!file_exists($sqlFile) || filemtime($sqlFile) < time() - self::SQL_FILE_TTL) {
$cfg = $this->config->get('database.connections.' . self::DB_CONN);
$this->generateSqlFile($cfg, $sqlFile);
}
}
/**
* @param $cfg
* @param string $sqlFile
*/
private function generateSqlFile($cfg, string $sqlFile): void
{
// create a tmp database, if it doesn't exist
DB::statement('DROP DATABASE IF EXISTS ' . $cfg['database']);
DB::statement('CREATE DATABASE ' . $cfg['database']);
// run the migrations on that database
$this->call('migrate', ['--database' => self::DB_CONN]);
// dump the state of the database to a sql file
$command = sprintf(
'mysqldump --column-statistics=0 -h %s --port=%s -u %s -p\'%s\' %s > %s',
$cfg['host'],
$cfg['port'],
$cfg['username'],
$cfg['password'],
$cfg['database'],
$sqlFile
);
exec($command);
}
}
<?php
namespace Tests;
use Illuminate\Contracts\Console\Kernel;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
abstract class TestCase extends BaseTestCase
{
use Concern\TraitCreatesApplication;
protected $baseUrl = 'http://localhost';
public function __construct($name = null, array $data = [], $dataName = '')
{
$this->afterApplicationCreatedCallbacks[] = function () {
$this->artisan('test:reset');
$this->app[Kernel::class]->setArtisan(null);
};
parent::__construct($name, $data, $dataName);
}
}
<?php
declare(strict_types=1);
namespace App\Console\Commands\Test;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
class TestResetCommand extends Command
{
private const SQL_FILENAME = 'tmp.sql';
protected $signature = 'test:reset';
public function handle()
{
// replace the current db with the tmp
DB::unprepared(file_get_contents(storage_path(self::SQL_FILENAME)));
}
}
<?php
require_once __DIR__.'/../bootstrap/autoload.php';
// prepare database
// setup tmp database from migrations
(new class() {
use \Tests\Concern\TraitCreatesApplication;
})->createApplication()[\Illuminate\Contracts\Console\Kernel::class]->call('test:bootstrap');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment