【问题标题】:Laravel factories slowing down testing due to nested relationships由于嵌套关系,Laravel 工厂减慢了测试速度
【发布时间】: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


【解决方案1】:

事实证明 Faker 的 image()真的很慢。我将 UserFactory 中的 'avatar' => $this->faker->image(), 替换为 'avatar' => null,,现在我的整个测试套件运行时间仅超过三秒,如果我并行运行它们,则运行一秒。

【讨论】:

    猜你喜欢
    • 2016-06-25
    • 2021-03-08
    • 1970-01-01
    • 2019-04-01
    • 2021-07-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-11
    相关资源
    最近更新 更多