【发布时间】:2022-01-08 18:50:57
【问题描述】:
就上下文而言,我正在开发基于 RNG 的赛车运动模拟器,因为没有更好的术语。用户可以创建宇宙(想想现实生活中的国际汽联),在宇宙中他们可以创建系列(想想 F1、F2、F3 等),并且在每个系列中他们可以创建季节。在其中的每一个中,用户都可以创建额外的模型;
在 Universe 中,用户可以创建团队和驱动程序。
在一个赛季中,用户可以使用他们在任何 Universe 之外添加的赛道、参赛者(基于他们在父 Universe 中创建的团队)创建一个日历,并且他们可以向这些参赛者添加驱动程序(基于创建的驱动程序),我称之为“阵容”。
我对这些关系的测试越深入,我需要通过工厂创建的模型就越多才能正确测试,并且测试运行所需的时间就越长。我有一个非常简单的测试来验证 Universe 所有者可以将驱动程序添加到属于该 Universe 的参赛者;
test('a universe owner can add drivers to entrants', function () {
$user = User::factory()->create();
$season = createSeasonForUser($user);
$driver = Driver::factory()->for($season->universe)->create();
$entrant = Entrant::factory()->for($season)->create();
$this->actingAs($user)
->post(route('seasons.lineups.store', [$season]), [
'driver_id' => $driver->id,
'entrant_id' => $entrant->id,
'number' => 2,
])
->assertRedirect(route('seasons.lineups.index', [$season]));
$this->assertDatabaseCount('lineups', 1);
$this->assertCount(1, $entrant->drivers);
$this->assertCount(1, $season->drivers);
});
我有两个辅助函数可以快速创建属于特定用户的系列和/或季节;
function createSeriesForUser(User $user): Series
{
return Series::factory()->for(Universe::factory()->for($user)->create())->create();
}
function createSeasonForUser(User $user): Season
{
$series = createSeriesForUser($user);
return Season::factory()->for($series)->create();
}
如您所见,为了测试流程的一部分,我需要通过工厂创建六个模型(其中一些工厂有时会调用更多工厂)。我运行了五次测试,对测试的每个部分(工厂、实际请求和断言)进行计时,工厂平均占用 1.9 秒,其余测试占用 0.015 秒,这并不对我来说似乎不对。
理想情况下,我会在运行每个测试文件之前创建所有必需的数据库条目,但我知道这是不好的做法。还有其他方法可以加快测试速度吗?可悲的是,我无法减少关系的嵌套或复杂性,因为这些只是我正在构建的网站的要求。
或者,这种方法通常是否是测试控制器功能的正确方法,还是可以以不同的方式完成?
为了不让问题过于混乱,here's 一个包含所有当前工厂的 pastebin
【问题讨论】:
-
首先,将这些“帮助程序”移动到一个只有在您拥有
required-dev(composer) 时才能加载和使用的类,这样您就可以防止有人调用这些外部测试。 . 第二,你能展示一下每个工厂在创造什么吗?我创建了更多的工厂和关系,每次测试我都没有以500ms结束,所以我认为你的工厂内部有些东西需要很多时间。你能为每个工厂的创建计时吗? -
辅助函数在
Pest.php文件中,执行它们的唯一方法是当有人已经拥有 CLI 访问权限时,在这种情况下我遇到了更大的问题。我已经为所有当前工厂附加了一个粘贴箱,但是直到今天晚些时候我才能对它们进行计时。 -
检查工厂后,我看不到任何需要 1.9 秒的东西,但我确实看到您没有正确定义它们。您必须使用
Model::factory()而不是Model::factory()->create()->id,检查documentation,也许这就是问题所在。还要检查我与您共享的代码之后的第二个代码,您将了解如何操作内容(您已经完成了$model = Model::factory()->create();然后在任何地方都使用了它,您必须使用文档上的第二个代码。 -
我会试一试(删除
create()->id),但不太清楚你评论的第二部分是什么意思。你能详细说明一下吗?
标签: testing phpunit laravel-8 factory php-pest