如果您的架构是最新的,则
特征不会迁移您的数据库。相反,它只会在数据库事务中执行测试。Illuminate\Foundation\Testing\RefreshDatabase
我使用的是 Laravel 10,我认为它在我的项目中无法正常工作。
由于项目迁移需要大约 1 分钟才能执行(
php artisan migrate:fresh --env testing
),我有一个本地测试数据库,我会保持最新状态以快速运行测试,但测试执行总是花费 至少 1 分钟,就好像它正在运行所有在运行测试之前进行迁移。
我需要测试一段代码是否落入
catch(Exception $e)
分支,并且由于这段代码从数据库检索结果,我想在所有setUp
之后更改表名称以使其抛出异常,并且工作了。SQLSTATE[42S02]: Base table or view not found
:这意味着该表仍然具有新的错误名称,因此看起来它不是要进行的单个测试包装在迁移中,但所有测试都在同一个测试类中,但这与之前的数据库操作(例如正在创建的实例)冲突,不影响后续测试。
我真的不知道哪里出了问题。
我将其作为答案而不是评论,以便我可以放置代码并使其更加明显:
关于文档具有误导性,您是正确的,请记住,您原来的帖子链接的是 Laravel 11.x 文档而不是 10.x(我已经修复了该问题),但他们仍然说同样的事情。
这是 Laravel 10 的 源代码:
public function refreshDatabase()
{
$this->beforeRefreshingDatabase();
$this->usingInMemoryDatabase()
? $this->refreshInMemoryDatabase()
: $this->refreshTestDatabase();
$this->afterRefreshingDatabase();
}
如您所见,您有一个
before
钩子、迁移运行和一个 after
钩子。两个钩子都是空的,您可以在测试中添加代码来干扰该特征。
refreshTestDatabase()
方法执行的内容:
protected function refreshTestDatabase()
{
if (! RefreshDatabaseState::$migrated) {
$this->artisan('migrate:fresh', $this->migrateFreshUsing());
$this->app[Kernel::class]->setArtisan(null);
RefreshDatabaseState::$migrated = true;
}
$this->beginDatabaseTransaction();
}
你可以看到它正在利用
RefreshDatabaseState
,它是一个简单的静态类,并且没有预先设置或以任何方式操作。因此 RefreshDatabaseState::$migrated
在第一次运行时始终为 false
,因此它将运行其中的代码,在本例中为 migrate:fresh
。
我从未采用过你的方法,但你可以尝试加入
before
钩子,然后手动检查是否运行了所有迁移,如下所示:
// In your test define exactly this
protected function beforeRefreshingDatabase()
{
$this->artisan('migrate');
\Illuminate\Foundation\Testing\RefreshDatabaseState::$migrated = true;
}
通过这种方式,我们可以自动迁移数据库(如果缺少任何运行),然后我们告诉特征它已经完成,无需
migrate:fresh
。请记住,它可能无法像运行时那样正常工作$this->app[Kernel::class]->setArtisan(null);
,我不知道为什么,而且我真的不想运行它。
migrate:status
并检查是否所有迁移都已运行,但如果缺少任何状态代码,它不会给我们状态代码,因此比较困难,因为您需要读取输出并检查它,而不是真的很想要。
简化的解决方案是:
migrate
命令自动运行缺失的迁移,只需将该命令添加到 setUp
,它可以在基类上或在该特定测试上\Illuminate\Foundation\Testing\DatabaseTransactions
作为 RefreshDatabase
,在我们的代码之后,正是使用在另一个特征中,只是开始一个交易如果您想要此解决方案,只需在测试中包含
DatabaseTransactions
,但请记住在基本测试类中的 migrate
上自动运行 setUp
,或者始终通过 CLI 保持最新状态,就是这样!