如何为laravel测试提供数据库迁移的种子?

时间:2017-02-20 16:52:40

标签: php laravel testing laravel-migrations laravel-seeding

Laravel的documentation建议使用DatabaseMigrations特征在测试之间迁移和回滚数据库。

use Illuminate\Foundation\Testing\DatabaseMigrations;

class ExampleTest extends TestCase
{
    use DatabaseMigrations;

    /**
     * A basic functional test example.
     *
     * @return void
     */
    public function testBasicExample()
    {
        $response = $this->get('/');

        // ...
    }
}

但是,我有一些种子数据,我想用我的测试。如果我跑:

php artisan migrate --seed

然后它适用于第一次测试,但它无法进行后续测试。这是因为特征回滚了迁移,当它再次运行迁移时,它不会为数据库设定种子。如何通过迁移运行数据库种子?

7 个答案:

答案 0 :(得分:20)

我花了一些时间来解决这个问题,所以I thought I'd share

如果您查看DatabaseMigrations trait的源代码,那么您会看到它有一个由runDatabaseMigrations setUp调用并注册回调的函数runs before every test在拆解时运行。

您可以通过对该函数进行别名来排序"extend" the trait,在原始名称下使用您的逻辑(artisan db:seed)重新声明一个新函数,并调用其中的别名。

use Illuminate\Foundation\Testing\DatabaseMigrations;

class ExampleTest extends TestCase
{
    use DatabaseMigrations {
        runDatabaseMigrations as baseRunDatabaseMigrations;
    }

    /**
     * Define hooks to migrate the database before and after each test.
     *
     * @return void
     */
    public function runDatabaseMigrations()
    {
        $this->baseRunDatabaseMigrations();
        $this->artisan('db:seed');
    }

    /**
     * A basic functional test example.
     *
     * @return void
     */
    public function testBasicExample()
    {
        $response = $this->get('/');

        // ...
    }
}

答案 1 :(得分:11)

您需要做的就是在setUp函数中进行工匠调用<?php use Illuminate\Foundation\Testing\DatabaseMigrations; class ExampleTest extends TestCase { use DatabaseMigrations; public function setUp(): void { parent::setUp(); $this->artisan('db:seed'); } /** * A basic functional test example. * * @return void */ public function testBasicExample() { $response = $this->get('/'); // ... } }

--Adding New Column with Default Value
ALTER TABLE TABLENAME 
ADD COLUMNNAME DATATYPE NULL|NOT NULL DEFAULT (DEFAULT_VALUE)

参考:https://laravel.com/docs/5.6/testing#creating-and-running-tests

答案 2 :(得分:9)

在 Laravel 8 中,如果您使用 RefreshDatabase trait,您可以使用以下命令从测试用例中调用种子:

use Illuminate\Foundation\Testing\RefreshDatabase;

class ExampleTest extends TestCase
{
    use RefreshDatabase;

    /**
     * A basic functional test example.
     *
     * @return void
     */
    public function testBasicExample()
    {
        // Run the DatabaseSeeder...
        $this->seed();

        // Run a specific seeder...
        $this->seed(OrderStatusSeeder::class);

        $response = $this->get('/');

        // ...
    }
}

有关更多信息/示例,请参阅文档: https://laravel.com/docs/8.x/database-testing#running-seeders

答案 3 :(得分:3)

我知道这个问题已经被回答过几次了,但是我没有看到这个特殊的答案,所以我想把它扔进去。

在laravel中有一段时间(至少从v5.5开始),TestCase类中有一种方法专门用于调用数据库种子程序:

https://laravel.com/api/5.7/Illuminate/Foundation/Testing/TestCase.html#method_seed

使用此方法,您只需调用$this->seed('MySeederName');即可启动播种机。

因此,如果您希望此种子播发器在每次测试之前启动,则可以在测试类中添加以下setUp函数:

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

最终结果与:

 $this->artisan('db:seed',['--class' => 'MySeederName'])

Artisan::call('db:seed', ['--class' => 'MySeederName'])

但是语法(在我看来)更加简洁。

答案 4 :(得分:1)

如果您使用的是RefreshDatabase测试特征:

abstract class TestCase extends BaseTestCase
{
    use CreatesApplication, RefreshDatabase {
        refreshDatabase as baseRefreshDatabase;
    }

    public function refreshDatabase()
    {
        $this->baseRefreshDatabase();

        // Seed the database on every database refresh.
        $this->artisan('db:seed');
    }
}

答案 5 :(得分:0)

如果您希望绕过Artisan的本机DatabaseMigrations和播种/迁移方法,这是一个替代解决方案。您可以创建自己的特征来为数据库设定种子:

namespace App\Traits;

use App\Models\User;
use App\Models\UserType;

trait DatabaseSetup 
{

    public function seedDatabase()
    {
        $user = $this->createUser();
    }

    public function createUser()
    {
        return factory(User::class)->create([
            'user_type_id' => function () {
                return factory(UserType::class)->create()->id;
            }
        ]);
    }

    public function getVar() {
        return 'My Data';
    }
}

然后在你的测试中调用它:

use App\Traits\DatabaseSetup;

class MyAwesomeTest extends TestCase
{
    use DatabaseSetup;
    use DatabaseTransactions;

    protected $reusableVar;

    public function setUp()
    {
        parent::setUp();
        $this->seedDatabase();
        $this->reusableVar = $this->getVar();
    }

    /**
     * @test
     */
    public function test_if_it_is_working()
    {
        $anotherUser = $this->createUser();
        $response = $this->get('/');
        $this->seeStatusCode(200);
    }

}

答案 6 :(得分:0)

在 Laravel 8 中,RefreshDatabase 现在正在寻找一个名为“seed”的布尔属性。

    /** 
     * Illuminate\Foundation\Testing\RefreshDatabase
     * Determine if the seed task should be run when refreshing the database.
     *
     * @return bool
     */
    protected function shouldSeed()
    {
        return property_exists($this, 'seed') ? $this->seed : false;
    }

只需为您的测试类提供受保护的属性 $seed 并将其设置为 true(如果您希望播种)。

class ProjectControllerTest extends TestCase
{

    protected $seed = true;
    public function testCreateProject()
    {
        $project = Project::InRandomOrder()->first();
        $this->assertInstanceOf($project,Project::class);
    }

这种方法的好处在于,单个测试不会在每次运行时都进行播种。只有种子必要的测试才会建立数据库。