Laravel でキューに入れられたジョブをテストするためのヒント

Mary-Kate Olsen
リリース: 2024-09-19 22:20:33
オリジナル
358 人が閲覧しました

Laravel アプリケーションを使用する場合、コマンドが負荷の高いタスクを実行する必要があるシナリオに遭遇するのが一般的です。メインプロセスのブロックを避けるために、キューで処理できるジョブにタスクをオフロードすることを決定することもできます。

例を見てみましょう。コマンド app:import-users が大きな CSV ファイルを読み取り、エントリごとにユーザーを作成する必要があると想像してください。コマンドは次のようになります:

/* ImportUsersCommand.php */

namespace App\Console\Commands;

/*...*/

class ImportUsersCommand extends Command
{
    protected $signature = 'app:import-users';

    public function handle()
    {
        dispatch(new ImportUsersJob());

        $this->line('Users imported successfully.');
        $this->line('There are: ' . User::count(). ' Users.');
    }
}
ログイン後にコピー

この例では、コマンドはファイルの読み取りとユーザーの作成を処理するジョブをディスパッチします。 ImportUsersJob.php は次のようになります:

/* ImportUsersJob.php */

namespace App\Jobs;

/*...*/

class ImportUsersJob implements ShouldQueue
{
    public function handle(FileReader $reader): void
    {   
        foreach($reader->read('users.csv') as $data) {
            User::create([
                'name' => $data['name'], 
                'email' => $data['email'],
            ]);
        }
    }
}
ログイン後にコピー

この機能をテストする場合、コマンドの一般的なテストは次のようになります。

/* ImportUsersCommandTest.php */

namespace Tests\Feature;

/*...*/

class ImportUsersCommandTest extends TestCase
{
    use RefreshDatabase;

    public function test_it_processes_the_file(): void
    {
        Storage::fake('local')->put('users.csv', "...");

        $this->artisan('app:import-users')
            ->expectsOutput('Users imported successfully.')
            ->expectsOutput('There are: 10 Users.')
            ->assertSuccessful();

        $this->assertDatabaseCount('users', 10);
    }
}
ログイン後にコピー

一見すると、このテストは完璧に機能しているように見えます。テスト スイートを実行すると、成功した結果が表示されます:

Tips for testing queued jobs in Laravel

現実世界の処刑

ただし、実際の環境で app:import-users コマンドを実行すると、予期しない結果が得られる可能性があります。

Tips for testing queued jobs in Laravel

ご覧のとおり、コマンド出力はデータベースにユーザーが 0 人しかいないことを示しています。では、なぜこのようなことが起こるのでしょうか?

その理由は、ジョブがキューにディスパッチされるため、コマンドの実行と同期して実行されないためです。ユーザーは、後でキューがジョブを処理するときにのみ作成されます。

なぜテストに合格するのでしょうか?

テスト スイートはデフォルトで同期キュー ドライバーを使用します。つまり、ジョブはテスト中に同期的に処理されます。その結果、ジョブはすぐに実行され、すべてが期待どおりに機能していることがわかります。

この動作はテスト環境では許容されますが、実際の結果は運用環境の QUEUE_CONNECTION 構成に依存することを認識することが重要です。また、プロジェクトの要件を考慮すると、ジョブが非同期キューで処理されることがわかっているかもしれません。

この違いを理解したら、「偽陽​​性」を回避するためにテストを改善したくなるかもしれません。

ジョブがディスパッチされることをテストする

まず、ジョブが同期的に処理されるか非同期的に処理されるかに関係なく、コマンドが実際にジョブをディスパッチすることを確認することが重要です。それをテストする方法は次のとおりです:

/* ImportUsersCommandTest.php */

namespace Tests\Feature;

/*...*/

class ImportUsersCommandTest extends TestCase
{    
    public function test_it_dispatches_the_job(): void
    {
        Queue:fake();

        $this->artisan('app:import-users')
            ->expectsOutput('Process has been queued.')
            ->assertSuccessful();

        Queue::assertPushed(ImportUsersJob::class);
    }
}
ログイン後にコピー

ジョブが処理されたことをテストする

ジョブがディスパッチされたことを確認したら、別のテストでジョブによって実行される実際の作業をテストできます。ジョブのテストを構成する方法は次のとおりです:

/* ImportUsersJobTest.php */

namespace Tests\Feature;

/*...*/

class ImportUsersJobTest extends TestCase
{
    use refreshDatabase;

    public function test_it_processes_the_file()
    {
        Storage::fake('local')->put('users.csv', "...");

        app()->call([new ImportUsersJob(), 'handle']);

        $this->assertDatabaseCount('users', 10);
    }
}

ログイン後にコピー

これにより、ジョブがキューによって処理されるか同期的に処理されるかに関係なく、必要な作業が確実に実行されます。

特殊なケースの処理

現実世界と同様に、特殊なケースが発生する可能性があるため、それらに備えておく必要があります。

Laravel のキュー システムは、ワーカーの設定に従って、例外が発生するとジョブを再試行します。再試行回数を超えると、ジョブは失敗としてマークされます。

それでは、ファイルが存在しない場合はどうなるでしょうか?入力を検証し、必要に応じて例外をスローすることで、このようなエッジケースに対処する必要があります。

仕事でこれに対処する方法は次のとおりです:

/* ImportUsersJobTest.php */

namespace App\Jobs;

/*...*/

class ImportUsersJob implements ShouldQueue
{
    use Queueable;

    public function handle(FileReader $reader): void
    {   
        if(!Storage::disk('local')->exists('users.csv')){
            throw new Exception('The users.csv file doesn\'t exist.')
        }

        foreach($reader->read('users.csv') as $data) {
            User::create([
                'name' => $data['name'], 
                'email' => $data['email'],
            ]);
        }
    }
}
ログイン後にコピー

このシナリオをテストする方法は次のとおりです:

/* ImportUsersJobTest.php */

namespace Tests\Feature;

/*...*/

class ImportUsersJobTest extends TestCase
{
    use refreshDatabase;

    /*...*/

    public function test_it_fails_when_file_doesnt_exist(): void
    {
        Storage::fake('local');

        $this->expectException(Exception::class);
        $this->expectExceptionMessage('The users.csv file doesn\'t exist.');

        dispatch(new ImportUsersJob());
    }
}

ログイン後にコピー

最終的な考え

このアプローチにより、テストは現実世界でジョブがどのように処理されるかをより正確に反映するようになります。
コントローラーがジョブをキューにディスパッチする場合、またはイベント リスナーがキューに登録されている場合にも、同じ戦略を適用できます。
いつものように、プロジェクトやチームに合わせてこれらのプラクティスを調整してください。

ぜひご意見をお聞かせください!

以上がLaravel でキューに入れられたジョブをテストするためのヒントの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!