Conseils pour tester les tâches en file d'attente dans Laravel

Mary-Kate Olsen
Libérer: 2024-09-19 22:20:33
original
458 Les gens l'ont consulté

Lorsque vous travaillez avec des applications Laravel, il est courant de rencontrer des scénarios dans lesquels une commande doit effectuer une tâche coûteuse. Pour éviter de bloquer le processus principal, vous pouvez décider de décharger la tâche vers une tâche pouvant être traitée par une file d'attente.

Prenons un exemple. Imaginez la commande app:import-users doit lire un gros fichier CSV et créer un utilisateur pour chaque entrée. Voici à quoi pourrait ressembler la commande :

/* 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.');
    }
}
Copier après la connexion

Dans cet exemple, la commande dispatche un job pour gérer la lecture du fichier et la création des utilisateurs. Voici à quoi pourrait ressembler le fichier 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'],
            ]);
        }
    }
}
Copier après la connexion

Lors du test de cette fonctionnalité, un test typique de la commande pourrait ressembler à ceci :

/* 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);
    }
}
Copier après la connexion

À première vue, ce test semble fonctionner parfaitement. L'exécution de la suite de tests montre un résultat réussi :

Tips for testing queued jobs in Laravel

Exécution dans le monde réel

Cependant, lorsque vous exécutez la commande app:import-users dans un environnement réel, vous pouvez obtenir un résultat inattendu :

Tips for testing queued jobs in Laravel

Comme vous pouvez le voir, le résultat de la commande indique qu'il y a 0 utilisateur dans la base de données. Alors, pourquoi cela arrive-t-il ?

La raison est que le travail est distribué dans une file d'attente, il ne s'exécute donc pas de manière synchrone avec l'exécution de la commande. Les utilisateurs ne seront créés que lorsque la file d'attente traitera le travail ultérieurement.

Pourquoi le test réussit-il ?

La suite de tests utilise le pilote de file d'attente de synchronisation par défaut, ce qui signifie que les tâches sont traitées de manière synchrone pendant le test. En conséquence, le travail s'exécute immédiatement, donnant l'idée que tout fonctionne comme prévu.

Bien que ce comportement soit acceptable dans l'environnement de test, il est important de reconnaître que les résultats réels dépendent de la configuration QUEUE_CONNECTION dans votre environnement de production. Et compte tenu des exigences de votre projet, vous savez peut-être que le travail sera traité dans une file d'attente asynchrone.

Une fois que vous aurez pris conscience de cette distinction, vous souhaiterez peut-être améliorer vos tests pour éviter les « faux positifs ».

Tester votre travail est expédié

Tout d’abord, il est important de vérifier que la commande distribue réellement la tâche, que la tâche soit traitée de manière synchrone ou asynchrone. Voici comment tester cela :

/* 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);
    }
}
Copier après la connexion

Le test de votre travail est traité

Une fois que vous avez confirmé que le travail est expédié, vous pouvez tester le travail réel effectué par le travail dans un test séparé. Voici comment vous pourriez structurer le test pour le poste :

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

Copier après la connexion

Cela garantit que le travail effectue le travail nécessaire, qu'il soit traité par une file d'attente ou de manière synchrone.

Gestion des cas extrêmes

Comme dans la vraie vie, des cas extrêmes peuvent survenir et vous devriez être prêt à y faire face.

Le système de file d'attente de Laravel, selon la configuration de vos travailleurs, réessayera les tâches lorsqu'une exception se produit, et si les tentatives sont dépassées, la tâche sera marquée comme ayant échoué.

Alors, que se passe-t-il si le fichier n’existe pas ? Vous devez gérer de tels cas extrêmes en validant les entrées et en lançant des exceptions si nécessaire.

Voici comment vous pourriez gérer cela dans votre travail :

/* 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'],
            ]);
        }
    }
}
Copier après la connexion

Voici comment tester ce scénario :

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

Copier après la connexion

Réflexions finales

Cette approche garantit que vos tests reflètent plus précisément la manière dont les tâches seront traitées dans le monde réel.
La même stratégie peut être appliquée lorsqu'un contrôleur distribue une tâche dans une file d'attente ou lorsqu'un écouteur d'événement est mis en file d'attente.
Comme toujours, ajustez ces pratiques en fonction de votre projet et de votre équipe.

J'aimerais entendre vos pensées !

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:dev.to
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal