From 79c6f6774eecf77aef8ed5e2f270551a6f378f1d Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 11 Apr 2017 11:20:36 -0500 Subject: [PATCH] Unify database testing traits with a new FreshDatabase trait. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- .../Foundation/Console/stubs/test.stub | 4 +- .../Foundation/Testing/FreshDatabase.php | 100 ++++++++++++++++++ .../Foundation/Testing/TestCase.php | 4 + 3 files changed, 105 insertions(+), 3 deletions(-) create mode 100644 src/Illuminate/Foundation/Testing/FreshDatabase.php diff --git a/src/Illuminate/Foundation/Console/stubs/test.stub b/src/Illuminate/Foundation/Console/stubs/test.stub index dd804dc9a315..d5ce59b88fbc 100644 --- a/src/Illuminate/Foundation/Console/stubs/test.stub +++ b/src/Illuminate/Foundation/Console/stubs/test.stub @@ -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 { diff --git a/src/Illuminate/Foundation/Testing/FreshDatabase.php b/src/Illuminate/Foundation/Testing/FreshDatabase.php new file mode 100644 index 000000000000..db983b8f33fd --- /dev/null +++ b/src/Illuminate/Foundation/Testing/FreshDatabase.php @@ -0,0 +1,100 @@ +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]; + } +} diff --git a/src/Illuminate/Foundation/Testing/TestCase.php b/src/Illuminate/Foundation/Testing/TestCase.php index 9b9318f209d3..6d12009bbc8e 100755 --- a/src/Illuminate/Foundation/Testing/TestCase.php +++ b/src/Illuminate/Foundation/Testing/TestCase.php @@ -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(); }