„Wenn ein Arbeiter seine Arbeit gut machen will, muss er zuerst seine Werkzeuge schärfen.“ – Konfuzius, „Die Gespräche des Konfuzius. Lu Linggong“
Titelseite > Programmierung > Tipps zum Testen von Jobs in der Warteschlange in Laravel

Tipps zum Testen von Jobs in der Warteschlange in Laravel

Veröffentlicht am 05.11.2024
Durchsuche:743

Bei der Arbeit mit Laravel-Anwendungen kommt es häufig vor, dass ein Befehl eine kostspielige Aufgabe ausführen muss. Um eine Blockierung des Hauptprozesses zu vermeiden, können Sie die Aufgabe auf einen Job verlagern, der von einer Warteschlange verarbeitet werden kann.

Lassen Sie uns ein Beispiel durchgehen. Stellen Sie sich vor, der Befehl app:import-users müsste eine große CSV-Datei lesen und für jeden Eintrag einen Benutzer erstellen. So könnte der Befehl aussehen:

/* 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.');
    }
}

In diesem Beispiel sendet der Befehl einen Job, der das Lesen der Datei und das Erstellen von Benutzern übernimmt. So könnte die ImportUsersJob.php aussehen:

/* 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'],
            ]);
        }
    }
}

Beim Testen dieser Funktion könnte ein typischer Test für den Befehl so aussehen:

/* 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);
    }
}

Auf den ersten Blick scheint dieser Test perfekt zu funktionieren. Das Ausführen der Testsuite zeigt ein erfolgreiches Ergebnis:

Tips for testing queued jobs in Laravel

Ausführung in der realen Welt

Wenn Sie jedoch den Befehl app:import-users in einer realen Umgebung ausführen, erhalten Sie möglicherweise ein unerwartetes Ergebnis:

Tips for testing queued jobs in Laravel

Wie Sie sehen können, zeigt die Befehlsausgabe an, dass sich in der Datenbank 0 Benutzer befinden. Also, warum passiert das?

Der Grund dafür ist, dass der Job an eine Warteschlange gesendet wird und daher nicht synchron mit der Befehlsausführung ausgeführt wird. Die Benutzer werden erst erstellt, wenn die Warteschlange den Job später verarbeitet.

Warum besteht der Test?

Die Testsuite verwendet standardmäßig den Synchronisierungswarteschlangentreiber, was bedeutet, dass Jobs während des Tests synchron verarbeitet werden. Dadurch wird der Job sofort ausgeführt, was den Eindruck vermittelt, dass alles wie erwartet funktioniert.

Während dieses Verhalten in der Testumgebung akzeptabel ist, ist es wichtig zu erkennen, dass reale Ergebnisse von der QUEUE_CONNECTION-Konfiguration in Ihrer Produktionsumgebung abhängen. Und angesichts Ihrer Projektanforderungen wissen Sie möglicherweise, dass der Auftrag in einer asynchronen Warteschlange verarbeitet wird.

Sobald Sie sich dieser Unterscheidung bewusst sind, möchten Sie möglicherweise Ihre Tests verbessern, um „falsch positive Ergebnisse“ zu vermeiden.

Die Prüfung Ihres Auftrags wird versandt

Zunächst ist es wichtig zu überprüfen, ob der Befehl den Job tatsächlich auslöst, unabhängig davon, ob der Job synchron oder asynchron verarbeitet wird. So testen Sie das:

/* 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);
    }
}

Die Prüfung Ihres Jobs wird bearbeitet

Sobald Sie bestätigt haben, dass der Job versandt wurde, können Sie die tatsächliche Arbeit des Jobs in einem separaten Test testen. So könnten Sie den Test für die Stelle strukturieren:

/* 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);
    }
}

Dadurch wird sichergestellt, dass der Job die erforderliche Arbeit ausführt, unabhängig davon, ob er von einer Warteschlange oder synchron verarbeitet wird.

Umgang mit Randfällen

Wie im wirklichen Leben können Randfälle auftreten und Sie sollten darauf vorbereitet sein.

Das Warteschlangensystem von Laravel wird je nach Konfiguration Ihrer Mitarbeiter Aufträge wiederholen, wenn eine Ausnahme auftritt, und wenn die Anzahl der Wiederholungsversuche überschritten wird, wird der Auftrag als fehlgeschlagen markiert.

Was passiert also, wenn die Datei nicht existiert? Sie müssen solche Randfälle bewältigen, indem Sie Eingaben validieren und bei Bedarf Ausnahmen auslösen.

So könnten Sie in Ihrem Job damit umgehen:

/* 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'],
            ]);
        }
    }
}

So würden Sie dieses Szenario testen:

/* 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());
    }
}

Letzte Gedanken

Dieser Ansatz stellt sicher, dass Ihre Tests genauer widerspiegeln, wie Aufträge in der realen Welt verarbeitet werden.
Die gleiche Strategie kann angewendet werden, wenn ein Controller einen Job an eine Warteschlange sendet oder wenn ein Ereignis-Listener in der Warteschlange steht.
Passen Sie diese Vorgehensweisen wie immer an Ihr Projekt und Ihr Team an.

Ich würde gerne Ihre Meinung hören!

Freigabeerklärung Dieser Artikel ist abgedruckt unter: https://dev.to/eduarguz/tips-for-testing-queued-jobs-in-laravel-4c77?1 Bei Verstößen wenden Sie sich bitte an [email protected], um ihn zu löschen
Neuestes Tutorial Mehr>

Haftungsausschluss: Alle bereitgestellten Ressourcen stammen teilweise aus dem Internet. Wenn eine Verletzung Ihres Urheberrechts oder anderer Rechte und Interessen vorliegt, erläutern Sie bitte die detaillierten Gründe und legen Sie einen Nachweis des Urheberrechts oder Ihrer Rechte und Interessen vor und senden Sie ihn dann an die E-Mail-Adresse: [email protected] Wir werden die Angelegenheit so schnell wie möglich für Sie erledigen.

Copyright© 2022 湘ICP备2022001581号-3