Hendrik Jan
Hendrik Jan

Reputation: 4908

Laravel phpunit how to use diffent migrations for tests

I am trying to set up tests in Laravel, but I want to run different migrations from those that usually run.

The migrations that I run to initiate the database imports data from a production environment.
For testing I want to use a different database called "test", and I want to fill this test database with test data, not production data.

I added a "testing" connection to config/database.php which uses the "test" database:

'connections' => [

        'mysql' => [
            'database' => env('DB_DATABASE', 'forge'),
            ...
        ],

        'testing' => [
            'database' => 'test',
            ...
        ],
],

And I setup phpunit.xml to use this "testing" connection:

<?xml version="1.0" encoding="UTF-8"?>
<phpunit ...>
    ...
    <php>
        <env name="DB_CONNECTION" value="testing"/>
        ...
    </php>
</phpunit>

Now I want to initialize this "test" database with test data, using migrations from a different folder than the default.

I can use the normal migrations like this:

<?php

namespace Tests;

use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
use Illuminate\Foundation\Testing\DatabaseMigrations;

abstract class TestCase extends BaseTestCase
{
    use DatabaseMigrations;

    public function setUp(): void
    {
        parent::setUp();
        $this->seed();
    }
}

But this uses the default folder database/migrations. I would like to put the testing migrations in folder tests/database/migrations.

Is there a way to let use DatabaseMigrations; use migrations from another folder?

Upvotes: 6

Views: 7416

Answers (3)

jdubwelch
jdubwelch

Reputation: 21

The RefreshDatabase trait has a method called migrateUsing which will overload the parameters that it uses when running the migrations. I changed to a specific test migration file for a single test by passing it in as the --path parameter to the migration.

namespace Tests\Unit;

use Tests\TestCase;
use App\Models\Traits\HasUuid;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Testing\RefreshDatabase;

class HasUuidTest extends TestCase
{
    use RefreshDatabase;

    protected function migrateUsing()
    {
        return [
            '--path' => 'tests/migrations/2022_03_15_220516_create_test_uuid_table.php'
        ];
    }

    public function test_has_uuid()
    {
        $model = new TestUuid;
        $this->assertEmpty($model->id);
        $model->save();
        $this->assertNotEmpty($model->id);
    }
}

class TestUuid extends Model
{
    use HasUuid;
}

Upvotes: 1

omitobi
omitobi

Reputation: 7334

You might need to override runDatabaseMigrations method in DatabaseMigrations trait and set the app's database path from there before your migrations run.

The runDatabaseMigrations method might end up looking like this:

use DatabaseMigrations { runDatabaseMigrations as runMigration; }

    public function runDatabaseMigrations()
    {
        $this->app->useDatabasePath(base_path('tests/database')); //example path
//        dump($this->app->databasePath());
        $this->runMigration();
    }

Or you can set in the boot method of your AppService provider:

    if (config('app.env') === 'testing') { //Laravel automatically set env to 'testing' when running test
        $this->app->useDatabasePath(base_path('tests/database'));
    }

The migration will look for a sub-folder of 'tests/database' called "migrations".

PS: There will be side effect to this if you're have some other code or folder in the default database folder. Example, your factory class there will not be found for this test class.

Upvotes: 11

mrhn
mrhn

Reputation: 18976

Artisan migrate has a path option, you have to make your own trait to have similar functionality. I'm thinking something like this.

trait PathDatabaseMigrations {

    public function runDatabaseMigrations()
    {
        // optimal 
        $path = 'tests/database/migrations';

        $this->artisan('migrate:fresh', ['--path' => $path,]);

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

        $this->beforeApplicationDestroyed(function () {
            $this->artisan('migrate:rollback', ['--path' => $path,]);

            RefreshDatabaseState::$migrated = false;
        });
    }
}

Upvotes: 1

Related Questions