我有一个 Laravel 4 测试类,其中包含一些测试,我想在运行测试之前为其数据库播种。使用 setup() 函数为每个测试重新设定种子需要很长时间。但是,当我尝试在静态 setupBeforeClass() 函数或构造函数中进行播种时,我显然无法使用 $this->seed() 方法。
但是我也不能使用编程 Artisan 命令,因为当我这样做时,我会收到以下错误:
PHP Fatal error: Class 'Artisan' not found in <test class name>.
这是我想用来播种的代码:
Artisan::call('migrate:refresh');
Artisan::call('db:seed', array('--class'=>'TestSeeder');
请让我知道如何在每次测试 class 而不是每次测试 case
为数据库播种一次实现类似效果的“即兴”但非常干净的方法是在
setUp
中执行此操作,但让它运行仅一次(类似于setupBeforeClass
所做的),如下所示:
use Illuminate\Support\Facades\Artisan;
class ExampleTest extends TestCase {
protected static $db_inited = false;
protected static function initDB()
{
echo "\n---initDB---\n"; // proof it only runs once per test TestCase class
Artisan::call('migrate');
// ...more db init stuff, like seeding etc.
}
public function setUp()
{
parent::setUp();
if (!static::$db_inited) {
static::$db_inited = true;
static::initDB();
}
}
// ...tests go here...
}
...这是我的解决方案,它看起来足够简单并且工作正常,解决了每次测试运行之前播种和重建数据库结构的性能问题。但请记住,进行测试的“正确”方法可以让您最大程度地相信您的测试方法不会以隐藏错误的方式微妙地相互依赖,即在每个测试方法之前重新播种您的数据库,因此只需将如果您能承受性能损失,请用普通的
setUp
播种代码(对于我的测试用例,我负担不起,但是 ymmv...)。
我也遇到了同样的问题并用这个解决了
passthru('cd ' . __DIR__ . '/../.. & php artisan migrate:refresh & db:seed --class=TestSeeder');
这是迄今为止我发现的最好的解决方案
class ExampleTest extends TestCase {
/**
* This method is called before
* any test of TestCase class executed
* @return void
*/
public static function setUpBeforeClass()
{
parent::setUpBeforeClass();
print "\nSETTING UP DATABASE\n";
shell_exec('php artisan migrate --seed');
}
/**
* This method is called after
* all tests of TestCase class executed
* @return void
*/
public static function tearDownAfterClass()
{
shell_exec('php artisan migrate:reset');
print "\nDESTROYED DATABASE\n";
parent::tearDownAfterClass();
}
/** tests goes here **/ }
更新: 拉拉维尔 5,6,7,8,9 https://laravel.com/docs/9.x/database-testing
use RefreshDatabase;
已过时:
这个特性是重置数据库的好方法
<?php namespace Tests; use Illuminate\Support\Facades\Artisan; trait MigrateFreshAndSeedOnce { /** * If true, setup has run at least once. * @var boolean */ protected static $setUpHasRunOnce = false; /** * After the first run of setUp "migrate:fresh --seed" * @return void */ public function setUp() : void { parent::setUp(); if (!static::$setUpHasRunOnce) { Artisan::call('migrate:fresh'); Artisan::call( 'db:seed', ['--class' => 'CompleteTestDbSeeder'] //add your seed class ); static::$setUpHasRunOnce = true; } } }
你现在可以做:
protected function setUp()
{
parent::setUp();
$this->seed();
}
在您的
setUp()
测试方法中。
seed()
方法接受播种器类作为参数。
public function seed($class = 'DatabaseSeeder')
{
$this->artisan('db:seed', ['--class' => $class]);
return $this;
}
在 Laravel 10 中,你不需要
setupBeforeClass
方法来实现此目的。相反,您可以使用 RefreshDatabase
特征。在运行第一个测试之前,它将回滚并重新运行所有迁移,并且如果在测试类中指定了 $seed = true
属性,则将运行播种器。此外,每个测试都将在事务内执行。例如:
<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\CreatesApplication;
use Tests\TestCase;
class ExampleTest extends TestCase
{
use CreatesApplication, RefreshDatabase;
protected $seed = true;
public function test_something(): void
{
// some code...
}
}
有关详细信息,请参阅 Running Seeders 部分和 RefreshDatabase 特征的源代码。