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:
Wenn Sie jedoch den Befehl app:import-users in einer realen Umgebung ausführen, erhalten Sie möglicherweise ein unerwartetes Ergebnis:
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.
Die Testsuite verwendet standardmäßig den Synchronisierungswarteschlangentreiber, was bedeutet, dass Aufträge 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.
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); } }
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.
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 mit solchen Grenzfällen umgehen, 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()); } }
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!
Das obige ist der detaillierte Inhalt vonTipps zum Testen von Jobs in der Warteschlange in Laravel. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!