laravel testing: database reset with seeding
Testing a Laravel application has a low barrier to entry compared to other PHP frameworks . What happens when you want to nuke the database between tests? I thought I’d share a solution here.
feature testing
One of the great features Laravel provides is the ability to
refresh
your database after each test. This has been really useful, but I needed to
test verbs like DELETE
and a simple php artisan migrate:fresh
isn’t all
that useful when you have seeds that add information to your database that your
tests rely on.
The class Illuminate\Foundation\Testing\RefreshDatabase
has a method used to
action the refresh refreshTestDatabase which just calls out to artisan
for
the migrate:fresh
command. Step in my nice little override:
// tests/ResetsDatabase.php
<?php
namespace Tests;
use Illuminate\Contracts\Console\Kernel;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\RefreshDatabaseState;
trait ResetsDatabase {
use RefreshDatabase;
protected function refreshTestDatabase()
{
if (! RefreshDatabaseState::$migrated) {
$this->artisan('migrate:fresh', $this->shouldDropViews() ? [
'--drop-views' => true,
] : []);
$this->artisan('db:seed', []);
$this->artisan('db:seed', [
'--class' => 'TestDatabaseSeeder',
]);
$this->app[Kernel::class]->setArtisan(null);
RefreshDatabaseState::$migrated = true;
}
$this->beginDatabaseTransaction();
}
}
You can use this in your tests the same way you would the RefreshDatabase class. But instead of just refreshing the database, you will get db:seed for free along with any test seeds you want to run.
// tests/Feature/UserApiTest.php
<?php
namespace Tests\Feature;
use Tests\ResetsDatabase;
use Tests\TestCase;
class UserApiTest extends TestCase {
use ResetsDatabase;
}
what about dusk?
The same can be achieved in dusk [https://laravel.com/docs/5.7/dusk] with a similar change in the DatabaseMigrations trait provided for resetting the database.
// tests/ResetsDatabaseInDusk.php
<?php
namespace Tests;
use Illuminate\Contracts\Console\Kernel;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\RefreshDatabaseState;
trait ResetsDatabaseInDusk {
use DatabaseMigrations;
protected function runDatabaseMigrations()
{
$this->artisan('migrate:fresh', [
'--drop-views' => true,
]);
$this->artisan('db:seed', []);
$this->artisan('db:seed', [
'--class' => 'TestDatabaseSeeder',
]);
$this->app[Kernel::class]->setArtisan(null);
$this->beforeApplicationDestroyed(function () {
$this->artisan('migrate:rollback');
RefreshDatabaseState::$migrated = false;
});
}
}
This will do the same as the previous trait but for your Browser tests.