Skip to content

Instantly share code, notes, and snippets.

@Solomon04
Last active April 6, 2023 06:55
Show Gist options
  • Save Solomon04/0a26b7ed8f4fad4ed7f59cd2dc6b852a to your computer and use it in GitHub Desktop.
Save Solomon04/0a26b7ed8f4fad4ed7f59cd2dc6b852a to your computer and use it in GitHub Desktop.
Seamlessly setup a test database within the PHPUnit + Laravel environment
APP_NAME="TDD"
APP_ENV=testing
APP_DEBUG=true
APP_KEY=base64:dOal46K64jWx6dQAIIKACbeMH99iqW0HryeT+3Jkoj0=
LOG_CHANNEL=stack
DB_CONNECTION=mysql
DB_HOST=mysql_test
DB_DATABASE=tdd
DB_USERNAME=sail
DB_PASSWORD=password
FILESYSTEM_DRIVER=local
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=120
MAIL_MAILER=log
<?php
namespace Tests;
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:fresh --seed');
$this->app[Kernel::class]->setArtisan(null);
}
protected function setupTestDatabase()
{
if (!static::$migrated) {
$this->whenMigrationsChange(function() {
$this->artisan('migrate:fresh --seed');
$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);
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
bootstrap="vendor/autoload.php"
colors="true"
>
<testsuites>
<testsuite name="Unit">
<directory suffix="Test.php">./tests/Unit</directory>
</testsuite>
<testsuite name="Feature">
<directory suffix="Test.php">./tests/Feature</directory>
</testsuite>
</testsuites>
<coverage processUncoveredFiles="true">
<include>
<directory suffix=".php">./app</directory>
</include>
</coverage>
<php>
<env name="APP_ENV" value="testing"/>
</php>
</phpunit>
<?php
namespace Tests;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
abstract class TestCase extends BaseTestCase
{
use CreatesApplication, DatabaseSetup;
/**
* Setup the test environment.
*
* @return void
*/
protected function setUp(): void
{
parent::setUp();
$this->setupDatabase();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment