在 Laravel 測試排隊作業的技巧

Mary-Kate Olsen
發布: 2024-09-19 22:20:33
原創
302 人瀏覽過

在使用 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 的佇列系統會根據你的 Workers 配置,在發生異常時重試作業,如果重試次數超過,作業將被標記為失敗。

那麼,如果文件不存在會發生什麼事?您需要透過驗證輸入並在必要時引發異常來處理此類邊緣情況。

以下是您在工作中可以如何處理此問題的方法:

/* 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中文網其他相關文章!

來源:dev.to
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!