RefreshDatabase.php
TLDR
The provided file RefreshDatabase.php
is a trait located in the Illuminate\Foundation\Testing
namespace. It defines methods for refreshing the test database before and after each test.
Methods
refreshDatabase
This method is responsible for refreshing the test database before and after each test. It calls the beforeRefreshingDatabase
, usingInMemoryDatabase
, restoreInMemoryDatabase
, refreshTestDatabase
, and afterRefreshingDatabase
methods.
usingInMemoryDatabase
This method determines if an in-memory database is being used. It checks the configuration to see if the database connection is set to :memory:
.
restoreInMemoryDatabase
This method restores the in-memory database between tests.
refreshTestDatabase
This method refreshes a conventional test database. It performs a fresh migration and begins a database transaction.
beginDatabaseTransaction
This method begins a database transaction on the testing database.
connectionsToTransact
This method returns an array of the database connections that should have transactions.
beforeRefreshingDatabase
This method is called before the database has started refreshing. It can be used to perform any necessary preparation work.
afterRefreshingDatabase
This method is called once the database has finished refreshing. It can be used to perform any necessary cleanup work.
END
<?php
namespace Illuminate\Foundation\Testing;
use Illuminate\Contracts\Console\Kernel;
use Illuminate\Foundation\Testing\Traits\CanConfigureMigrationCommands;
trait RefreshDatabase
{
use CanConfigureMigrationCommands;
/**
* Define hooks to migrate the database before and after each test.
*
* @return void
*/
public function refreshDatabase()
{
$this->beforeRefreshingDatabase();
if ($this->usingInMemoryDatabase()) {
$this->restoreInMemoryDatabase();
}
$this->refreshTestDatabase();
$this->afterRefreshingDatabase();
}
/**
* Determine if an in-memory database is being used.
*
* @return bool
*/
protected function usingInMemoryDatabase()
{
$default = config('database.default');
return config("database.connections.$default.database") === ':memory:';
}
/**
* Restore the in-memory database between tests.
*
* @return void
*/
protected function restoreInMemoryDatabase()
{
$database = $this->app->make('db');
foreach ($this->connectionsToTransact() as $name) {
if (isset(RefreshDatabaseState::$inMemoryConnections[$name])) {
$database->connection($name)->setPdo(RefreshDatabaseState::$inMemoryConnections[$name]);
}
}
}
/**
* Refresh a conventional test database.
*
* @return void
*/
protected function refreshTestDatabase()
{
if (! RefreshDatabaseState::$migrated) {
$this->artisan('migrate:fresh', $this->migrateFreshUsing());
$this->app[Kernel::class]->setArtisan(null);
RefreshDatabaseState::$migrated = true;
}
$this->beginDatabaseTransaction();
}
/**
* Begin a database transaction on the testing database.
*
* @return void
*/
public function beginDatabaseTransaction()
{
$database = $this->app->make('db');
$this->app->instance('db.transactions', $transactionsManager = new DatabaseTransactionsManager);
foreach ($this->connectionsToTransact() as $name) {
$connection = $database->connection($name);
$connection->setTransactionManager($transactionsManager);
if ($this->usingInMemoryDatabase()) {
RefreshDatabaseState::$inMemoryConnections[$name] ??= $connection->getPdo();
}
$dispatcher = $connection->getEventDispatcher();
$connection->unsetEventDispatcher();
$connection->beginTransaction();
$connection->setEventDispatcher($dispatcher);
}
$this->beforeApplicationDestroyed(function () use ($database) {
foreach ($this->connectionsToTransact() as $name) {
$connection = $database->connection($name);
$dispatcher = $connection->getEventDispatcher();
$connection->unsetEventDispatcher();
$connection->rollBack();
$connection->setEventDispatcher($dispatcher);
$connection->disconnect();
}
});
}
/**
* The database connections that should have transactions.
*
* @return array
*/
protected function connectionsToTransact()
{
return property_exists($this, 'connectionsToTransact')
? $this->connectionsToTransact : [null];
}
/**
* Perform any work that should take place before the database has started refreshing.
*
* @return void
*/
protected function beforeRefreshingDatabase()
{
// ...
}
/**
* Perform any work that should take place once the database has finished refreshing.
*
* @return void
*/
protected function afterRefreshingDatabase()
{
// ...
}
}