Skip to content

Commit

Permalink
Unify database testing traits with a new FreshDatabase trait.
Browse files Browse the repository at this point in the history
This trait is based on work by @adamwathan on a better testing workflow
when interacting with databases. In general, the goal is to have a
single trait that “just works” out of the box regardless of whether you
are using an in-memory SQLite database or a conventional MySQL /
Postgres database when testing. The database will be migrated to make
sure it is up to date and then a transaction will be started to make
any records added during the test temporary. Like the database
transaction trait, the current transaction will be rolled back at the
end of each test.
  • Loading branch information
taylorotwell committed Apr 11, 2017
1 parent 8877cf6 commit 79c6f67
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 3 deletions.
4 changes: 1 addition & 3 deletions src/Illuminate/Foundation/Console/stubs/test.stub
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
namespace DummyNamespace;

use Tests\TestCase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Foundation\Testing\FreshDatabase;

class DummyClass extends TestCase
{
Expand Down
100 changes: 100 additions & 0 deletions src/Illuminate/Foundation/Testing/FreshDatabase.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
<?php

namespace Illuminate\Foundation\Testing;

use Illuminate\Contracts\Console\Kernel;

trait FreshDatabase
{
/**
* Indicates if the test database has been migrated.
*
* @var bool
*/
protected static $migrated = false;

/**
* Define hooks to migrate the database before and after each test.
*
* @return void
*/
public function refreshDatabase()
{
$this->usingInMemoryDatabase()
? $this->refreshInMemoryDatabase()
: $this->refreshTestDatabase();
}

/**
* Determine if an in-memory database is being used.
*
* @return bool
*/
protected function usingInMemoryDatabase()
{
return config('database.connections')[
config('database.default')
]['database'] == ':memory:';
}

/**
* Refresh the in-memory database.
*
* @return void
*/
protected function refreshInMemoryDatabase()
{
$this->artisan('migrate');

$this->app[Kernel::class]->setArtisan(null);
}

/**
* Refresh a conventional test database.
*
* @return void
*/
protected function refreshTestDatabase()
{
if (! static::$migrated) {
$this->artisan('migrate:fresh');

$this->app[Kernel::class]->setArtisan(null);

static::$migrated = true;
}

$this->beginDatabaseTransaction();
}

/**
* Begin a database transaction on the testing database.
*
* @return void
*/
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();
}
});
}

/**
* The database connections that should have transactions.
*
* @return array
*/
protected function connectionsToTransact()
{
return property_exists($this, 'connectionsToTransact')
? $this->connectionsToTransact : [null];
}
}
4 changes: 4 additions & 0 deletions src/Illuminate/Foundation/Testing/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ protected function setUpTraits()
{
$uses = array_flip(class_uses_recursive(static::class));

if (isset($uses[FreshDatabase::class])) {
$this->refreshDatabase();
}

if (isset($uses[DatabaseMigrations::class])) {
$this->runDatabaseMigrations();
}
Expand Down

0 comments on commit 79c6f67

Please sign in to comment.